*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.18 1998/06/05 03:49:18 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.19 1998/07/08 14:04:10 thomas Exp $
*
*-------------------------------------------------------------------------
*/
List *p_target = tlist;
TargetEntry *tent = makeNode(TargetEntry);
-
if (sortgroupby->range) {
- Attr *missingTarget = (Attr *)makeNode(Attr);
- missingTarget->type = T_Attr;
+ Attr *missingAttr = (Attr *)makeNode(Attr);
+ missingAttr->type = T_Attr;
- missingTarget->relname = palloc(strlen(sortgroupby->range) + 1);
- strcpy(missingTarget->relname, sortgroupby->range);
+ missingAttr->relname = palloc(strlen(sortgroupby->range) + 1);
+ strcpy(missingAttr->relname, sortgroupby->range);
- missingTarget->attrs = lcons(makeString(sortgroupby->name), NIL);
+ missingAttr->attrs = lcons(makeString(sortgroupby->name), NIL);
- transformTargetId(pstate, (Node*)missingTarget, tent, sortgroupby->name, TRUE);
+ tent = transformTargetIdent(pstate, (Node *)missingAttr, tent,
+ &missingAttr->relname, NULL,
+ missingAttr->relname, TRUE);
}
else {
- Ident *missingTarget = (Ident *)makeNode(Ident);
- missingTarget->type = T_Ident;
+ Ident *missingIdent = (Ident *)makeNode(Ident);
+ missingIdent->type = T_Ident;
- missingTarget->name = palloc(strlen(sortgroupby->name) + 1);
- strcpy(missingTarget->name, sortgroupby->name);
+ missingIdent->name = palloc(strlen(sortgroupby->name) + 1);
+ strcpy(missingIdent->name, sortgroupby->name);
- transformTargetId(pstate, (Node*)missingTarget, tent, sortgroupby->name, TRUE);
+ tent = transformTargetIdent(pstate, (Node *)missingIdent, tent,
+ &missingIdent->name, NULL,
+ missingIdent->name, TRUE);
}
-
/* Add to the end of the target list */
while (lnext(p_target) != NIL) {
p_target = lnext(p_target);
Node *expr;
expr = ((TargetEntry *)lfirst(next_target))->expr;
- expr = coerce_target_expr(NULL, expr, itype, otype);
+ expr = CoerceTargetExpr(NULL, expr, itype, otype);
if (expr == NULL)
{
elog(ERROR,"Unable to transform %s to %s"
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/parse_relation.c,v 1.11 1998/02/26 04:33:34 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/parse_relation.c,v 1.12 1998/07/08 14:04:11 thomas Exp $
*
*-------------------------------------------------------------------------
*/
#include "catalog/pg_type.h"
#include "nodes/makefuncs.h"
#include "parser/parse_relation.h"
+#include "parser/parse_coerce.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
return (rd->rd_att->attrs[attid - 1]->atttypid);
}
-/*
- * handleTargetColname -
- * use column names from insert
+/* handleTargetColname()
+ * Use column names from insert.
*/
void
handleTargetColname(ParseState *pstate, char **resname,
checkTargetTypes(pstate, *resname, refname, colname);
}
-/*
- * checkTargetTypes -
- * checks value and target column types
+/* checkTargetTypes()
+ * Checks value and target column types.
*/
static void
checkTargetTypes(ParseState *pstate, char *target_colname,
resdomno_target = attnameAttNum(pstate->p_target_relation, target_colname);
attrtype_target = attnumTypeId(pstate->p_target_relation, resdomno_target);
+#if FALSE
+ if ((attrtype_id != attrtype_target)
+ || (get_atttypmod(rte->relid, resdomno_id) !=
+ get_atttypmod(pstate->p_target_relation->rd_id, resdomno_target)))
+ {
+ if (can_coerce_type(1, &attrtype_id, &attrtype_target))
+ {
+ Node *expr = coerce_type(pstate, expr, attrtype_id, attrtype_target);
+
+ elog(ERROR, "Type %s(%d) can be coerced to match target column %s(%d)",
+ colname, get_atttypmod(rte->relid, resdomno_id),
+ target_colname, get_atttypmod(pstate->p_target_relation->rd_id, resdomno_target));
+ }
+ else
+ {
+ elog(ERROR, "Type or size of %s(%d) does not match target column %s(%d)",
+ colname, get_atttypmod(rte->relid, resdomno_id),
+ target_colname, get_atttypmod(pstate->p_target_relation->rd_id, resdomno_target));
+ }
+ }
+#else
if (attrtype_id != attrtype_target)
elog(ERROR, "Type of %s does not match target column %s",
colname, target_colname);
get_atttypmod(pstate->p_target_relation->rd_id, resdomno_target))
elog(ERROR, "Length of %s is longer than length of target column %s",
colname, target_colname);
-
+#endif
}
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.16 1998/06/15 19:28:55 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.17 1998/07/08 14:04:11 thomas Exp $
*
*-------------------------------------------------------------------------
*/
#include "utils/syscache.h"
-static List *expandAllTables(ParseState *pstate);
-static char *figureColname(Node *expr, Node *resval);
+static List *ExpandAllTables(ParseState *pstate);
+static char *FigureColname(Node *expr, Node *resval);
static TargetEntry *
-make_targetlist_expr(ParseState *pstate,
- char *colname,
- Node *expr,
- List *arrayRef);
+MakeTargetlistExpr(ParseState *pstate,
+ char *colname,
+ Node *expr,
+ List *arrayRef);
Node *
-size_target_expr(ParseState *pstate,
- Node *expr,
- Oid attrtype,
- int16 attrtypmod);
+SizeTargetExpr(ParseState *pstate,
+ Node *expr,
+ Oid attrtype,
+ int16 attrtypmod);
-/*
- * transformTargetId - transforms an Ident Node to a Target Entry
- * Created this a function to allow the ORDER/GROUP BY clause be able
- * to construct a TargetEntry from an Ident.
+/* transformTargetIdent()
+ * Transforms an Ident Node to a Target Entry
+ * Created this function to allow the ORDER/GROUP BY clause to be able
+ * to construct a TargetEntry from an Ident.
*
- * resjunk = TRUE will hide the target entry in the final result tuple.
+ * resjunk = TRUE will hide the target entry in the final result tuple.
+ *
+ * Added more conversion logic to match up types from source to target.
+ * - thomas 1998-06-02
*/
-void
-transformTargetId(ParseState *pstate,
- Node *node,
- TargetEntry *tent,
- char *resname,
- int16 resjunk)
+TargetEntry *
+transformTargetIdent(ParseState *pstate,
+#if FALSE
+ Ident *ident,
+#else
+ Node *node,
+#endif
+ TargetEntry *tent,
+ char **resname,
+ char *refname,
+ char *colname,
+ int16 resjunk)
{
- Node *expr;
- Oid type_id;
- int16 type_mod;
+ Node *expr = NULL;
+ Oid attrtype_target;
+
+
+ if (pstate->p_is_insert)
+ {
+ if (pstate->p_insert_columns != NIL)
+ {
+ Ident *id = lfirst(pstate->p_insert_columns);
+
+ *resname = id->name;
+ pstate->p_insert_columns = lnext(pstate->p_insert_columns);
+ }
+ else
+ elog(ERROR, "insert: more expressions than target columns");
+ }
+
+ if (pstate->p_is_insert || pstate->p_is_update)
+ {
+ Oid attrtype_id;
+ int resdomno_id,
+ resdomno_target;
+ RangeTblEntry *rte;
+ char *target_colname;
+ int16 attrtypmod,
+ attrtypmod_target;
+
+ target_colname = *resname;
+
+ if (target_colname == NULL || colname == NULL)
+ return (tent);
+
+ if (refname != NULL)
+ rte = refnameRangeTableEntry(pstate, refname);
+ else
+ {
+ rte = colnameRangeTableEntry(pstate, colname);
+ if (rte == (RangeTblEntry *) NULL)
+ elog(ERROR, "attribute %s not found", colname);
+ refname = rte->refname;
+ }
+
+ resdomno_id = get_attnum(rte->relid, colname);
+ attrtype_id = get_atttype(rte->relid, resdomno_id);
+ attrtypmod = get_atttypmod(rte->relid, resdomno_id);
+
+ resdomno_target = attnameAttNum(pstate->p_target_relation, target_colname);
+ attrtype_target = attnumTypeId(pstate->p_target_relation, resdomno_target);
+ attrtypmod_target = get_atttypmod(pstate->p_target_relation->rd_id, resdomno_target);
+
+#ifdef PARSEDEBUG
+printf("transformTargetIdent- transform type %d to %d\n",
+ attrtype_id, attrtype_target);
+#endif
+ if ((attrtype_id != attrtype_target)
+ || ((attrtypmod_target >= 0) && (attrtypmod_target != attrtypmod)))
+ {
+ if (can_coerce_type(1, &attrtype_id, &attrtype_target))
+ {
+ expr = coerce_type(pstate, node, attrtype_id, attrtype_target);
+ expr = transformExpr(pstate, expr, EXPR_COLUMN_FIRST);
+ tent = MakeTargetlistExpr(pstate, *resname, expr, FALSE);
+ expr = tent->expr;
+ }
+ else
+ {
+#if TRUE
+ elog(ERROR, "Unable to convert %s to %s for column %s",
+ typeidTypeName(attrtype_id), typeidTypeName(attrtype_target),
+ target_colname);
+#else
+ elog(ERROR, "Type or size of %s(%d) does not match target column %s(%d)",
+ colname, attrtypmod, target_colname, attrtypmod_target);
+#endif
+ }
+ }
+ }
/*
* here we want to look for column names only, not
* relation names (even though they can be stored in
* Ident nodes, too)
*/
- expr = transformExpr(pstate, node, EXPR_COLUMN_FIRST);
- type_id = exprType(expr);
- if (nodeTag(expr) == T_Var)
- type_mod = ((Var *) expr)->vartypmod;
- else
- type_mod = -1;
- tent->resdom = makeResdom((AttrNumber) pstate->p_last_resno++,
- (Oid) type_id,
- type_mod,
- resname,
- (Index) 0,
- (Oid) 0,
- resjunk);
+ if (expr == NULL)
+ {
+ char *name;
+ int16 type_mod;
- tent->expr = expr;
- return;
-}
+ name = ((*resname != NULL)? *resname: colname);
+#ifdef PARSEDEBUG
+printf("transformTargetIdent- call transformIdent()\n");
+#endif
+#if FALSE
+ expr = transformIdent(pstate, (Node *) ident, EXPR_COLUMN_FIRST);
+#else
+ expr = transformExpr(pstate, node, EXPR_COLUMN_FIRST);
+#endif
+ attrtype_target = exprType(expr);
+ if (nodeTag(expr) == T_Var)
+ type_mod = ((Var *) expr)->vartypmod;
+ else
+ type_mod = -1;
-/*
- * transformTargetList -
- * turns a list of ResTarget's into a list of TargetEntry's
+#ifdef PARSEDEBUG
+printf("transformTargetIdent- attrtype_target = %d; type_mod = %d\n", attrtype_target, type_mod);
+#endif
+
+ tent->resdom = makeResdom((AttrNumber) pstate->p_last_resno++,
+ (Oid) attrtype_target,
+ type_mod,
+ name,
+ (Index) 0,
+ (Oid) 0,
+ resjunk);
+ tent->expr = expr;
+ }
+
+ return (tent);
+} /* transformTargetIdent() */
+
+
+/* transformTargetList()
+ * Turns a list of ResTarget's into a list of TargetEntry's.
*/
List *
transformTargetList(ParseState *pstate, List *targetlist)
while (targetlist != NIL)
{
- ResTarget *res = (ResTarget *) lfirst(targetlist);
- TargetEntry *tent = makeNode(TargetEntry);
+ ResTarget *res = (ResTarget *) lfirst(targetlist);
+ TargetEntry *tent = makeNode(TargetEntry);
switch (nodeTag(res->val))
{
case T_Ident:
{
char *identname;
+#if FALSE
char *resname;
+#endif
+#ifdef PARSEDEBUG
+printf("transformTargetList: decode T_Ident\n");
+#endif
identname = ((Ident *) res->val)->name;
- handleTargetColname(pstate, &res->name, NULL, identname);
- resname = (res->name) ? res->name : identname;
- transformTargetId(pstate, (Node*)res->val, tent, resname, FALSE);
+ tent = transformTargetIdent(pstate, (Node *)res->val, tent, &res->name, NULL, identname, FALSE);
break;
}
case T_ParamNo:
case T_A_Const:
case T_A_Expr:
{
- Node *expr = transformExpr(pstate, (Node *) res->val, EXPR_COLUMN_FIRST);
+ Node *expr = transformExpr(pstate, (Node *) res->val, EXPR_COLUMN_FIRST);
+#ifdef PARSEDEBUG
+printf("transformTargetList: decode T_Expr\n");
+#endif
handleTargetColname(pstate, &res->name, NULL, NULL);
/* note indirection has not been transformed */
if (pstate->p_is_insert && res->indirection != NIL)
constval = makeNode(Value);
constval->type = T_String;
constval->val.str = save_str;
- tent = make_targetlist_expr(pstate, res->name,
- (Node *) make_const(constval),
- NULL);
+ tent = MakeTargetlistExpr(pstate, res->name,
+ (Node *) make_const(constval),
+ NULL);
pfree(save_str);
}
else
* at the yacc grammar for why a name can be
* missing. -ay
*/
- colname = figureColname(expr, res->val);
+ colname = FigureColname(expr, res->val);
}
if (res->indirection)
{
}
}
res->name = colname;
- tent = make_targetlist_expr(pstate, res->name, expr,
- res->indirection);
+ tent = MakeTargetlistExpr(pstate, res->name, expr,
+ res->indirection);
}
break;
}
if (att->relname != NULL && !strcmp(att->relname, "*"))
{
if (tail_p_target == NIL)
- p_target = tail_p_target = expandAllTables(pstate);
+ p_target = tail_p_target = ExpandAllTables(pstate);
else
- lnext(tail_p_target) = expandAllTables(pstate);
+ lnext(tail_p_target) = ExpandAllTables(pstate);
while (lnext(tail_p_target) != NIL)
/* make sure we point to the last target entry */
* Target item is fully specified: ie.
* relation.attribute
*/
+#ifdef PARSEDEBUG
+printf("transformTargetList: decode T_Attr\n");
+#endif
result = ParseNestedFuncOrColumn(pstate, att, &pstate->p_last_resno, EXPR_COLUMN_FIRST);
handleTargetColname(pstate, &res->name, att->relname, attrname);
if (att->indirection != NIL)
Node *
-coerce_target_expr(ParseState *pstate,
- Node *expr,
- Oid type_id,
- Oid attrtype)
+CoerceTargetExpr(ParseState *pstate,
+ Node *expr,
+ Oid type_id,
+ Oid attrtype)
{
if (can_coerce_type(1, &type_id, &attrtype))
{
#ifdef PARSEDEBUG
-printf("parse_target: coerce type from %s to %s\n",
+printf("CoerceTargetExpr: coerce type from %s to %s\n",
typeidTypeName(type_id), typeidTypeName(attrtype));
#endif
expr = coerce_type(pstate, expr, type_id, attrtype);
{
Oid text_id = TEXTOID;
#ifdef PARSEDEBUG
-printf("parse_target: try coercing from %s to %s via text\n",
+printf("CoerceTargetExpr: try coercing from %s to %s via text\n",
typeidTypeName(type_id), typeidTypeName(attrtype));
#endif
if (type_id == TEXTOID)
expr = NULL;
return expr;
-} /* coerce_target_expr() */
+} /* CoerceTargetExpr() */
-/* size_target_expr()
+/* SizeTargetExpr()
* Apparently going to a fixed-length string?
* Then explicitly size for storage...
*/
Node *
-size_target_expr(ParseState *pstate,
- Node *expr,
- Oid attrtype,
- int16 attrtypmod)
+SizeTargetExpr(ParseState *pstate,
+ Node *expr,
+ Oid attrtype,
+ int16 attrtypmod)
{
int i;
HeapTuple ftup;
A_Const *cons;
#ifdef PARSEDEBUG
-printf("parse_target: ensure target fits storage\n");
+printf("SizeTargetExpr: ensure target fits storage\n");
#endif
funcname = typeidTypeName(attrtype);
oid_array[0] = attrtype;
for (i = 2; i < 8; i++) oid_array[i] = InvalidOid;
#ifdef PARSEDEBUG
-printf("parse_target: look for conversion function %s(%s,%s)\n",
+printf("SizeTargetExpr: look for conversion function %s(%s,%s)\n",
funcname, typeidTypeName(attrtype), typeidTypeName(INT4OID));
#endif
if (HeapTupleIsValid(ftup))
{
#ifdef PARSEDEBUG
-printf("parse_target: found conversion function for sizing\n");
+printf("SizeTargetExpr: found conversion function for sizing\n");
#endif
func = makeNode(FuncCall);
func->funcname = funcname;
#ifdef PARSEDEBUG
else
{
-printf("parse_target: no conversion function for sizing\n");
+printf("SizeTargetExpr: no conversion function for sizing\n");
}
#endif
return expr;
-} /* size_target_expr() */
+} /* SizeTargetExpr() */
-/* make_targetlist_expr()
- * Make a TargetEntry from an expression
- *
- * arrayRef is a list of transformed A_Indices
+/* MakeTargetlistExpr()
+ * Make a TargetEntry from an expression.
+ * arrayRef is a list of transformed A_Indices.
*
* For type mismatches between expressions and targets, use the same
* techniques as for function and operator type coersion.
* - thomas 1998-05-08
*/
static TargetEntry *
-make_targetlist_expr(ParseState *pstate,
+MakeTargetlistExpr(ParseState *pstate,
char *colname,
Node *expr,
List *arrayRef)
Resdom *resnode;
if (expr == NULL)
- elog(ERROR, "make_targetlist_expr: invalid use of NULL expression");
+ elog(ERROR, "MakeTargetlistExpr: invalid use of NULL expression");
type_id = exprType(expr);
if (nodeTag(expr) == T_Var)
else
typelem = attrtype;
- expr = coerce_target_expr(pstate, expr, type_id, typelem);
+ expr = CoerceTargetExpr(pstate, expr, type_id, typelem);
if (!HeapTupleIsValid(expr))
- {
elog(ERROR, "parser: attribute '%s' is of type '%s'"
" but expression is of type '%s'"
"\n\tYou will need to rewrite or cast the expression",
colname,
typeidTypeName(attrtype),
typeidTypeName(type_id));
- }
}
#ifdef PARSEDEBUG
-printf("parse_target: attrtypmod is %d\n", (int4) attrtypmod);
+printf("MakeTargetlistExpr: attrtypmod is %d\n", (int4) attrtypmod);
#endif
/* Apparently going to a fixed-length string?
* Then explicitly size for storage...
*/
if (attrtypmod > 0)
- expr = size_target_expr(pstate, expr, attrtype, attrtypmod);
+ expr = SizeTargetExpr(pstate, expr, attrtype, attrtypmod);
}
if (arrayRef != NIL)
attrtype = type_id;
attrtypmod = type_mod;
}
- tent = makeNode(TargetEntry);
+ tent = makeNode(TargetEntry);
resnode = makeResdom((AttrNumber) resdomno,
(Oid) attrtype,
attrtypmod,
tent->expr = expr;
return tent;
-} /* make_targetlist_expr() */
+} /* MakeTargetlistExpr() */
/*
}
/*
- * expandAllTables -
+ * ExpandAllTables -
* turns '*' (in the target list) into a list of attributes
* (of all relations in the range table)
*/
static List *
-expandAllTables(ParseState *pstate)
+ExpandAllTables(ParseState *pstate)
{
List *target = NIL;
List *legit_rtable = NIL;
}
/*
- * figureColname -
+ * FigureColname -
* if the name of the resulting column is not specified in the target
* list, we have to guess.
*
*/
static char *
-figureColname(Node *expr, Node *resval)
+FigureColname(Node *expr, Node *resval)
{
switch (nodeTag(expr))
{