diff options
Diffstat (limited to 'src/backend/parser')
-rw-r--r-- | src/backend/parser/gram.y | 81 | ||||
-rw-r--r-- | src/backend/parser/parse_clause.c | 248 | ||||
-rw-r--r-- | src/backend/parser/parse_target.c | 25 |
3 files changed, 185 insertions, 169 deletions
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index db4c9344d4f..6f4854c395b 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -10,7 +10,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.20 1998/08/04 17:37:48 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.21 1998/08/05 04:49:08 scrappy Exp $ * * HISTORY * AUTHOR DATE MAJOR EVENT @@ -103,6 +103,7 @@ Oid param_type(int t); /* used in parse_expr.c */ DefElem *defelt; ParamString *param; SortGroupBy *sortgroupby; + JoinUsing *joinusing; IndexElem *ielem; RangeVar *range; RelExpr *relexp; @@ -162,7 +163,7 @@ Oid param_type(int t); /* used in parse_expr.c */ sort_clause, sortby_list, index_params, index_list, name_list, from_clause, from_list, opt_array_bounds, nest_array_bounds, expr_list, attrs, res_target_list, res_target_list2, - def_list, opt_indirection, group_clause, groupby_list, TriggerFuncArgs + def_list, opt_indirection, group_clause, TriggerFuncArgs %type <node> func_return %type <boolean> set_opt @@ -171,7 +172,7 @@ Oid param_type(int t); /* used in parse_expr.c */ %type <list> union_clause, select_list %type <list> join_list -%type <sortgroupby> +%type <joinusing> join_using %type <boolean> opt_union %type <boolean> opt_table @@ -211,7 +212,6 @@ Oid param_type(int t); /* used in parse_expr.c */ %type <node> CreateAsElement %type <value> NumericOnly, FloatOnly, IntegerOnly %type <attr> event_object, attr -%type <sortgroupby> groupby %type <sortgroupby> sortby %type <ielem> index_elem, func_index %type <range> from_val @@ -2517,28 +2517,10 @@ sortby_list: sortby { $$ = lcons($1, NIL); } | sortby_list ',' sortby { $$ = lappend($1, $3); } ; -sortby: ColId OptUseOp +sortby: a_expr OptUseOp { $$ = makeNode(SortGroupBy); - $$->resno = 0; - $$->range = NULL; - $$->name = $1; - $$->useOp = $2; - } - | ColId '.' ColId OptUseOp - { - $$ = makeNode(SortGroupBy); - $$->resno = 0; - $$->range = $1; - $$->name = $3; - $$->useOp = $4; - } - | Iconst OptUseOp - { - $$ = makeNode(SortGroupBy); - $$->resno = $1; - $$->range = NULL; - $$->name = NULL; + $$->node = $1; $$->useOp = $2; } ; @@ -2570,40 +2552,10 @@ name_list: name { $$ = lappend($1,makeString($3)); } ; -group_clause: GROUP BY groupby_list { $$ = $3; } +group_clause: GROUP BY expr_list { $$ = $3; } | /*EMPTY*/ { $$ = NIL; } ; -groupby_list: groupby { $$ = lcons($1, NIL); } - | groupby_list ',' groupby { $$ = lappend($1, $3); } - ; - -groupby: ColId - { - $$ = makeNode(SortGroupBy); - $$->resno = 0; - $$->range = NULL; - $$->name = $1; - $$->useOp = NULL; - } - | ColId '.' ColId - { - $$ = makeNode(SortGroupBy); - $$->resno = 0; - $$->range = $1; - $$->name = $3; - $$->useOp = NULL; - } - | Iconst - { - $$ = makeNode(SortGroupBy); - $$->resno = $1; - $$->range = NULL; - $$->name = NULL; - $$->useOp = NULL; - } - ; - having_clause: HAVING a_expr { $$ = $2; @@ -2688,28 +2640,33 @@ join_list: join_using { $$ = lcons($1, NIL); } ; join_using: ColId - { - $$ = makeNode(SortGroupBy); + /* Changed from SortGroupBy parse node to new JoinUsing node. + * SortGroupBy no longer needs these structure members. + * + * Once, acknowledged, this comment can be removed by the + * developer(s) working on the JOIN clause. + * + * - daveh@insightdist.com 1998-07-31 + */ + { + $$ = makeNode(JoinUsing); $$->resno = 0; $$->range = NULL; $$->name = $1; - $$->useOp = NULL; } | ColId '.' ColId { - $$ = makeNode(SortGroupBy); + $$ = makeNode(JoinUsing); $$->resno = 0; $$->range = $1; $$->name = $3; - $$->useOp = NULL; } | Iconst { - $$ = makeNode(SortGroupBy); + $$ = makeNode(JoinUsing); $$->resno = $1; $$->range = NULL; $$->name = NULL; - $$->useOp = NULL; } ; diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c index 0e122999cbf..98eecb319a0 100644 --- a/src/backend/parser/parse_clause.c +++ b/src/backend/parser/parse_clause.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.22 1998/08/02 13:34:26 thomas Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.23 1998/08/05 04:49:09 scrappy Exp $ * *------------------------------------------------------------------------- */ @@ -28,9 +28,15 @@ #include "parser/parse_coerce.h" + +#define ORDER_CLAUSE 0 +#define GROUP_CLAUSE 1 + +static char *clauseText[] = {"ORDER", "GROUP"}; + static TargetEntry * -find_targetlist_entry(ParseState *pstate, - SortGroupBy *sortgroupby, List *tlist); +findTargetlistEntry(ParseState *pstate, Node *node, List *tlist, int clause); + static void parseFromClause(ParseState *pstate, List *frmList); @@ -65,7 +71,7 @@ makeRangeTable(ParseState *pstate, char *relname, List *frmList) /* * transformWhereClause - * transforms the qualification and make sure it is of type Boolean - * + * */ Node * transformWhereClause(ParseState *pstate, Node *a_expr) @@ -128,130 +134,182 @@ parseFromClause(ParseState *pstate, List *frmList) } /* - * find_targetlist_entry - + * findTargetlistEntry - * returns the Resdom in the target list matching the specified varname - * and range + * and range. If none exist one is created. + * + * Rewritten for ver 6.4 to handle expressions in the GROUP/ORDER BY clauses. + * - daveh@insightdist.com 1998-07-31 * */ static TargetEntry * -find_targetlist_entry(ParseState *pstate, SortGroupBy *sortgroupby, List *tlist) +findTargetlistEntry(ParseState *pstate, Node *node, List *tlist, int clause) { - List *i; - int real_rtable_pos = 0, - target_pos = 0; + List *l; + int rtable_pos = 0, + target_pos = 0, + targetlist_pos = 0; TargetEntry *target_result = NULL; + Value *val = NULL; + char *relname = NULL; + char *name = NULL; + Node *expr = NULL; + int relCnt = 0; + + /* Pull out some values before looping thru target list */ + switch(nodeTag(node)) + { + case T_Attr: + relname = ((Attr*)node)->relname; + val = (Value *)lfirst(((Attr*)node)->attrs); + name = strVal(val); + rtable_pos = refnameRangeTablePosn(pstate, relname, NULL); + relCnt = length(pstate->p_rtable); + break; + + case T_Ident: + name = ((Ident*)node)->name; + relCnt = length(pstate->p_rtable); + break; + + case T_A_Const: + val = &((A_Const*)node)->val; + + if (nodeTag(val) != T_Integer) + elog(ERROR, "Illegal Constant in %s BY", clauseText[clause]); + target_pos = intVal(val); + break; + + case T_FuncCall: + case T_A_Expr: + expr = transformExpr(pstate, node, EXPR_COLUMN_FIRST); + break; + + default: + elog(ERROR, "Illegal %s BY node = %d", clauseText[clause], nodeTag(node)); + } - if (sortgroupby->range != NULL) - real_rtable_pos = refnameRangeTablePosn(pstate, sortgroupby->range, NULL); - - foreach(i, tlist) + /* + * Loop through target entries and try to match to node + */ + foreach(l, tlist) { - TargetEntry *target = (TargetEntry *) lfirst(i); + TargetEntry *target = (TargetEntry *) lfirst(l); Resdom *resnode = target->resdom; Var *var = (Var *) target->expr; char *resname = resnode->resname; int test_rtable_pos = var->varno; - /* no name specified? then must have been a column number instead... */ - if (sortgroupby->name == NULL) + ++targetlist_pos; + + switch(nodeTag(node)) { - if (sortgroupby->resno == ++target_pos) + case T_Attr: + if (strcmp(resname, name) == 0 && rtable_pos == test_rtable_pos) { - target_result = target; - break; + /* Check for only 1 table & ORDER BY -ambiguity does not matter here */ + if (clause == ORDER_CLAUSE && relCnt == 1) + return target; + + if (target_result != NULL) + elog(ERROR, "%s BY '%s' is ambiguous", clauseText[clause], name); + else + target_result = target; + /* Stay in loop to check for ambiguity */ } - } - /* otherwise, try to match name... */ - else - { - /* same name? */ - if (strcmp(resname, sortgroupby->name) == 0) + break; + + case T_Ident: + if (strcmp(resname, name) == 0) { - if (sortgroupby->range != NULL) - { - if (real_rtable_pos == test_rtable_pos) - { - if (target_result != NULL) - elog(ERROR, "ORDER/GROUP BY '%s' is ambiguous", sortgroupby->name); - else - target_result = target; - } - } + /* Check for only 1 table & ORDER BY -ambiguity does not matter here */ + if (clause == ORDER_CLAUSE && relCnt == 1) + return target; + + if (target_result != NULL) + elog(ERROR, "%s BY '%s' is ambiguous", clauseText[clause], name); else - { - if (target_result != NULL) - elog(ERROR, "ORDER/GROUP BY '%s' is ambiguous", sortgroupby->name); - else - target_result = target; - } + target_result = target; + /* Stay in loop to check for ambiguity */ } - } - } + break; + case T_A_Const: + if (target_pos == targetlist_pos) + { + /* Can't be ambigious and we got what we came for */ + return target; + } + break; - /* No name specified and no target found? - * Then must have been an out-of-range column number instead... - * - thomas 1998-07-09 - */ - if ((sortgroupby->name == NULL) && (target_result == NULL)) - { - elog(ERROR, "ORDER/GROUP BY position %d is not in target list", - sortgroupby->resno); - } + case T_FuncCall: + case T_A_Expr: + if (equal(expr, target->expr)) + { + /* Check for only 1 table & ORDER BY -ambiguity does not matter here */ + if (clause == ORDER_CLAUSE) + return target; + + if (target_result != NULL) + elog(ERROR, "GROUP BY has ambiguous expression"); + else + target_result = target; + } + break; + default: + elog(ERROR, "Illegal %s BY node = %d", clauseText[clause], nodeTag(node)); + } + } - /* BEGIN add missing target entry hack. - * - * Prior to this hack, this function returned NIL if no target_result. - * Thus, ORDER/GROUP BY required the attributes be in the target list. - * Now it constructs a new target entry which is appended to the end of - * the target list. This target is set to be resjunk = TRUE so that + /* + * If no matches, construct a new target entry which is appended to the end + * of the target list. This target is set to be resjunk = TRUE so that * it will not be projected into the final tuple. - * daveh@insightdist.com 5/20/98 */ - if ((target_result == NULL) && (sortgroupby->name != NULL)) { - - List *p_target = tlist; - TargetEntry *tent = makeNode(TargetEntry); - - if (sortgroupby->range != NULL) { - Attr *missingAttr = (Attr *)makeNode(Attr); - missingAttr->type = T_Attr; - - missingAttr->relname = palloc(strlen(sortgroupby->range) + 1); - strcpy(missingAttr->relname, sortgroupby->range); - - missingAttr->attrs = lcons(makeString(sortgroupby->name), NIL); - - tent = transformTargetIdent(pstate, (Node *)missingAttr, tent, - &missingAttr->relname, NULL, - missingAttr->relname, TRUE); - } - else + if (target_result == NULL) + { + switch(nodeTag(node)) { - Ident *missingIdent = (Ident *)makeNode(Ident); - missingIdent->type = T_Ident; + case T_Attr: + target_result = transformTargetIdent(pstate, node, makeNode(TargetEntry), + &((Attr*)node)->relname, NULL, + ((Attr*)node)->relname, TRUE); + lappend(tlist, target_result); + break; - missingIdent->name = palloc(strlen(sortgroupby->name) + 1); - strcpy(missingIdent->name, sortgroupby->name); + case T_Ident: + target_result = transformTargetIdent(pstate, node, makeNode(TargetEntry), + &((Ident*)node)->name, NULL, + ((Ident*)node)->name, TRUE); + lappend(tlist, target_result); + break; - tent = transformTargetIdent(pstate, (Node *)missingIdent, tent, - &missingIdent->name, NULL, - missingIdent->name, TRUE); - } + case T_A_Const: + /* + * If we got this far, then must have been an out-of-range column number + */ + elog(ERROR, "%s BY position %d is not in target list", clauseText[clause], target_pos); + break; + + case T_FuncCall: + case T_A_Expr: + target_result = MakeTargetlistExpr(pstate, "resjunk", expr, FALSE, TRUE); + lappend(tlist, target_result); + break; - /* Add to the end of the target list */ - while (lnext(p_target) != NIL) { - p_target = lnext(p_target); + default: + elog(ERROR, "Illegal %s BY node = %d", clauseText[clause], nodeTag(node)); + break; } - lnext(p_target) = lcons(tent, NIL); - target_result = tent; } - /* END add missing target entry hack. */ return target_result; } + + + /* * transformGroupClause - * transform a Group By clause @@ -269,7 +327,7 @@ transformGroupClause(ParseState *pstate, List *grouplist, List *targetlist) TargetEntry *restarget; Resdom *resdom; - restarget = find_targetlist_entry(pstate, lfirst(grouplist), targetlist); + restarget = findTargetlistEntry(pstate, lfirst(grouplist), targetlist, GROUP_CLAUSE); grpcl->entry = restarget; resdom = restarget->resdom; @@ -328,7 +386,7 @@ printf("transformSortClause: entering\n"); TargetEntry *restarget; Resdom *resdom; - restarget = find_targetlist_entry(pstate, sortby, targetlist); + restarget = findTargetlistEntry(pstate, sortby->node, targetlist, ORDER_CLAUSE); #ifdef PARSEDEBUG printf("transformSortClause: find sorting operator for type %d\n", diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c index 7de957935d1..58dd3a28b35 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.19 1998/07/20 19:53:52 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.20 1998/08/05 04:49:11 scrappy Exp $ * *------------------------------------------------------------------------- */ @@ -32,11 +32,7 @@ static List *ExpandAllTables(ParseState *pstate); static char *FigureColname(Node *expr, Node *resval); -static TargetEntry * -MakeTargetlistExpr(ParseState *pstate, - char *colname, - Node *expr, - List *arrayRef); + Node * SizeTargetExpr(ParseState *pstate, Node *expr, @@ -129,7 +125,7 @@ printf("transformTargetIdent- transform type %d to %d\n", { expr = coerce_type(pstate, node, attrtype_id, attrtype_target); expr = transformExpr(pstate, expr, EXPR_COLUMN_FIRST); - tent = MakeTargetlistExpr(pstate, *resname, expr, FALSE); + tent = MakeTargetlistExpr(pstate, *resname, expr, FALSE, FALSE); expr = tent->expr; } else @@ -293,7 +289,7 @@ printf("transformTargetList: decode T_Expr\n"); constval->val.str = save_str; tent = MakeTargetlistExpr(pstate, res->name, (Node *) make_const(constval), - NULL); + NULL, FALSE); pfree(save_str); } else @@ -326,7 +322,7 @@ printf("transformTargetList: decode T_Expr\n"); } res->name = colname; tent = MakeTargetlistExpr(pstate, res->name, expr, - res->indirection); + res->indirection, FALSE); } break; } @@ -570,12 +566,17 @@ printf("SizeTargetExpr: no conversion function for sizing\n"); * For type mismatches between expressions and targets, use the same * techniques as for function and operator type coersion. * - thomas 1998-05-08 + * + * Added resjunk flag and made extern so that it can be use by GROUP/ + * ORDER BY a function or expersion not in the target_list + * - daveh@insightdist.com 1998-07-31 */ -static TargetEntry * +TargetEntry * MakeTargetlistExpr(ParseState *pstate, char *colname, Node *expr, - List *arrayRef) + List *arrayRef, + int16 resjunk) { Oid type_id, attrtype; @@ -698,7 +699,7 @@ printf("MakeTargetlistExpr: attrtypmod is %d\n", (int4) attrtypmod); colname, (Index) 0, (Oid) 0, - 0); + resjunk); tent = makeTargetEntry(resnode, expr); |