diff options
Diffstat (limited to 'src/backend/parser/parse_target.c')
-rw-r--r-- | src/backend/parser/parse_target.c | 294 |
1 files changed, 201 insertions, 93 deletions
diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c index 86b7474c200..ceb489990a7 100644 --- a/src/backend/parser/parse_target.c +++ b/src/backend/parser/parse_target.c @@ -7,7 +7,7 @@ * * * 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 $ * *------------------------------------------------------------------------- */ @@ -30,67 +30,169 @@ #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. - * daveh@insightdist.com 5/20/98 + * resjunk = TRUE will hide the target entry in the final result tuple. + * daveh@insightdist.com 5/20/98 + * + * 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) @@ -100,20 +202,23 @@ 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: @@ -121,8 +226,11 @@ transformTargetList(ParseState *pstate, List *targetlist) 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) @@ -183,9 +291,9 @@ transformTargetList(ParseState *pstate, List *targetlist) 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 @@ -201,7 +309,7 @@ transformTargetList(ParseState *pstate, List *targetlist) * 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) { @@ -217,8 +325,8 @@ transformTargetList(ParseState *pstate, List *targetlist) } } res->name = colname; - tent = make_targetlist_expr(pstate, res->name, expr, - res->indirection); + tent = MakeTargetlistExpr(pstate, res->name, expr, + res->indirection); } break; } @@ -240,9 +348,9 @@ transformTargetList(ParseState *pstate, List *targetlist) 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 */ @@ -291,6 +399,9 @@ transformTargetList(ParseState *pstate, List *targetlist) * 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) @@ -348,15 +459,15 @@ transformTargetList(ParseState *pstate, List *targetlist) 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); @@ -368,7 +479,7 @@ printf("parse_target: coerce type from %s to %s\n", { 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) @@ -385,18 +496,18 @@ printf("parse_target: try coercing from %s to %s via text\n", 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; @@ -407,7 +518,7 @@ size_target_expr(ParseState *pstate, 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; @@ -415,7 +526,7 @@ printf("parse_target: ensure target fits storage\n"); 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 @@ -429,7 +540,7 @@ printf("parse_target: look for conversion function %s(%s,%s)\n", 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; @@ -444,25 +555,24 @@ printf("parse_target: found conversion function for sizing\n"); #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) @@ -478,7 +588,7 @@ make_targetlist_expr(ParseState *pstate, 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) @@ -515,28 +625,26 @@ make_targetlist_expr(ParseState *pstate, 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) @@ -583,8 +691,8 @@ printf("parse_target: attrtypmod is %d\n", (int4) attrtypmod); attrtype = type_id; attrtypmod = type_mod; } - tent = makeNode(TargetEntry); + tent = makeNode(TargetEntry); resnode = makeResdom((AttrNumber) resdomno, (Oid) attrtype, attrtypmod, @@ -597,7 +705,7 @@ printf("parse_target: attrtypmod is %d\n", (int4) attrtypmod); tent->expr = expr; return tent; -} /* make_targetlist_expr() */ +} /* MakeTargetlistExpr() */ /* @@ -656,12 +764,12 @@ makeTargetNames(ParseState *pstate, List *cols) } /* - * 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; @@ -720,13 +828,13 @@ expandAllTables(ParseState *pstate) } /* - * 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)) { |