diff options
Diffstat (limited to 'src/backend/parser')
-rw-r--r-- | src/backend/parser/gram.y | 69 | ||||
-rw-r--r-- | src/backend/parser/parse_clause.c | 5 | ||||
-rw-r--r-- | src/backend/parser/parse_expr.c | 82 | ||||
-rw-r--r-- | src/backend/parser/parse_target.c | 42 | ||||
-rw-r--r-- | src/backend/parser/parse_type.c | 5 |
5 files changed, 135 insertions, 68 deletions
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index e908750f76a..78e81fbf562 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -11,7 +11,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.619 2008/08/28 23:09:47 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.620 2008/08/30 01:39:14 tgl Exp $ * * HISTORY * AUTHOR DATE MAJOR EVENT @@ -89,7 +89,7 @@ static bool QueryIsRule = FALSE; */ /*#define __YYSCLASS*/ -static Node *makeColumnRef(char *relname, List *indirection, int location); +static Node *makeColumnRef(char *colname, List *indirection, int location); static Node *makeTypeCast(Node *arg, TypeName *typename, int location); static Node *makeStringConst(char *str, int location); static Node *makeStringConstCast(char *str, int location, TypeName *typename); @@ -102,6 +102,7 @@ static Node *makeBoolAConst(bool state, int location); static FuncCall *makeOverlaps(List *largs, List *rargs, int location); static void check_qualified_name(List *names); static List *check_func_name(List *names); +static List *check_indirection(List *indirection); static List *extractArgTypes(List *parameters); static SelectStmt *findLeftmostSelect(SelectStmt *node); static void insertSelectOptions(SelectStmt *stmt, @@ -5144,9 +5145,7 @@ UnlistenStmt: | UNLISTEN '*' { UnlistenStmt *n = makeNode(UnlistenStmt); - n->relation = makeNode(RangeVar); - n->relation->relname = "*"; - n->relation->schemaname = NULL; + n->relation = NULL; $$ = (Node *)n; } ; @@ -5999,7 +5998,7 @@ insert_column_item: { $$ = makeNode(ResTarget); $$->name = $1; - $$->indirection = $2; + $$->indirection = check_indirection($2); $$->val = NULL; $$->location = @1; } @@ -6138,7 +6137,7 @@ set_target: { $$ = makeNode(ResTarget); $$->name = $1; - $$->indirection = $2; + $$->indirection = check_indirection($2); $$->val = NULL; /* upper production sets this */ $$->location = @1; } @@ -7842,7 +7841,7 @@ c_expr: columnref { $$ = $1; } { A_Indirection *n = makeNode(A_Indirection); n->arg = (Node *) p; - n->indirection = $2; + n->indirection = check_indirection($2); $$ = (Node *) n; } else @@ -7854,7 +7853,7 @@ c_expr: columnref { $$ = $1; } { A_Indirection *n = makeNode(A_Indirection); n->arg = $2; - n->indirection = $4; + n->indirection = check_indirection($4); $$ = (Node *)n; } else @@ -8409,7 +8408,7 @@ xml_attribute_el: a_expr AS ColLabel { $$ = makeNode(ResTarget); $$->name = $3; - $$->indirection = NULL; + $$->indirection = NIL; $$->val = (Node *) $1; $$->location = @1; } @@ -8417,7 +8416,7 @@ xml_attribute_el: a_expr AS ColLabel { $$ = makeNode(ResTarget); $$->name = NULL; - $$->indirection = NULL; + $$->indirection = NIL; $$->val = (Node *) $1; $$->location = @1; } @@ -8724,7 +8723,7 @@ indirection_el: } | '.' '*' { - $$ = (Node *) makeString("*"); + $$ = (Node *) makeNode(A_Star); } | '[' a_expr ']' { @@ -8833,7 +8832,7 @@ target_el: a_expr AS ColLabel | '*' { ColumnRef *n = makeNode(ColumnRef); - n->fields = list_make1(makeString("*")); + n->fields = list_make1(makeNode(A_Star)); n->location = @1; $$ = makeNode(ResTarget); @@ -9511,7 +9510,7 @@ SpecialRuleRelation: %% static Node * -makeColumnRef(char *relname, List *indirection, int location) +makeColumnRef(char *colname, List *indirection, int location) { /* * Generate a ColumnRef node, with an A_Indirection node added if there @@ -9533,23 +9532,30 @@ makeColumnRef(char *relname, List *indirection, int location) if (nfields == 0) { /* easy case - all indirection goes to A_Indirection */ - c->fields = list_make1(makeString(relname)); - i->indirection = indirection; + c->fields = list_make1(makeString(colname)); + i->indirection = check_indirection(indirection); } else { /* got to split the list in two */ - i->indirection = list_copy_tail(indirection, nfields); + i->indirection = check_indirection(list_copy_tail(indirection, + nfields)); indirection = list_truncate(indirection, nfields); - c->fields = lcons(makeString(relname), indirection); + c->fields = lcons(makeString(colname), indirection); } i->arg = (Node *) c; return (Node *) i; } + else if (IsA(lfirst(l), A_Star)) + { + /* We only allow '*' at the end of a ColumnRef */ + if (lnext(l) != NULL) + yyerror("improper use of \"*\""); + } nfields++; } /* No subscripting, so all indirection gets added to field list */ - c->fields = lcons(makeString(relname), indirection); + c->fields = lcons(makeString(colname), indirection); return (Node *) c; } @@ -9712,8 +9718,6 @@ check_qualified_name(List *names) { if (!IsA(lfirst(i), String)) yyerror("syntax error"); - else if (strcmp(strVal(lfirst(i)), "*") == 0) - yyerror("syntax error"); } } @@ -9731,12 +9735,31 @@ check_func_name(List *names) { if (!IsA(lfirst(i), String)) yyerror("syntax error"); - else if (strcmp(strVal(lfirst(i)), "*") == 0) - yyerror("syntax error"); } return names; } +/* check_indirection --- check the result of indirection production + * + * We only allow '*' at the end of the list, but it's hard to enforce that + * in the grammar, so do it here. + */ +static List * +check_indirection(List *indirection) +{ + ListCell *l; + + foreach(l, indirection) + { + if (IsA(lfirst(l), A_Star)) + { + if (lnext(l) != NULL) + yyerror("improper use of \"*\""); + } + } + return indirection; +} + /* extractArgTypes() * Given a list of FunctionParameter nodes, extract a list of just the * argument types (TypeNames) for input parameters only. This is what diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c index 7097ef50582..5285f0ba3d9 100644 --- a/src/backend/parser/parse_clause.c +++ b/src/backend/parser/parse_clause.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/parser/parse_clause.c,v 1.177 2008/08/28 23:09:47 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/parser/parse_clause.c,v 1.178 2008/08/30 01:39:14 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1181,7 +1181,8 @@ findTargetlistEntry(ParseState *pstate, Node *node, List **tlist, int clause) *---------- */ if (IsA(node, ColumnRef) && - list_length(((ColumnRef *) node)->fields) == 1) + list_length(((ColumnRef *) node)->fields) == 1 && + IsA(linitial(((ColumnRef *) node)->fields), String)) { char *name = strVal(linitial(((ColumnRef *) node)->fields)); int location = ((ColumnRef *) node)->location; diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c index 3c14cf1b527..8496e7291c1 100644 --- a/src/backend/parser/parse_expr.c +++ b/src/backend/parser/parse_expr.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.232 2008/08/28 23:09:47 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.233 2008/08/30 01:39:14 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -334,6 +334,13 @@ transformIndirection(ParseState *pstate, Node *basenode, List *indirection) if (IsA(n, A_Indices)) subscripts = lappend(subscripts, n); + else if (IsA(n, A_Star)) + { + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("row expansion via \"*\" is not supported here"), + parser_errposition(pstate, exprLocation(basenode)))); + } else { Assert(IsA(n, String)); @@ -403,10 +410,14 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref) { case 1: { - char *name = strVal(linitial(cref->fields)); + Node *field1 = (Node *) linitial(cref->fields); + char *name1; + + Assert(IsA(field1, String)); + name1 = strVal(field1); /* Try to identify as an unqualified column */ - node = colNameToVar(pstate, name, false, cref->location); + node = colNameToVar(pstate, name1, false, cref->location); if (node == NULL) { @@ -419,7 +430,7 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref) * have used VALUE as a column name in the past.) */ if (pstate->p_value_substitute != NULL && - strcmp(name, "value") == 0) + strcmp(name1, "value") == 0) { node = (Node *) copyObject(pstate->p_value_substitute); @@ -442,32 +453,40 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref) * PostQUEL-inspired syntax. The preferred form now is * "rel.*". */ - if (refnameRangeTblEntry(pstate, NULL, name, + if (refnameRangeTblEntry(pstate, NULL, name1, &levels_up) != NULL) - node = transformWholeRowRef(pstate, NULL, name, + node = transformWholeRowRef(pstate, NULL, name1, cref->location); else ereport(ERROR, (errcode(ERRCODE_UNDEFINED_COLUMN), errmsg("column \"%s\" does not exist", - name), + name1), parser_errposition(pstate, cref->location))); } break; } case 2: { - char *name1 = strVal(linitial(cref->fields)); - char *name2 = strVal(lsecond(cref->fields)); + Node *field1 = (Node *) linitial(cref->fields); + Node *field2 = (Node *) lsecond(cref->fields); + char *name1; + char *name2; + + Assert(IsA(field1, String)); + name1 = strVal(field1); /* Whole-row reference? */ - if (strcmp(name2, "*") == 0) + if (IsA(field2, A_Star)) { node = transformWholeRowRef(pstate, NULL, name1, cref->location); break; } + Assert(IsA(field2, String)); + name2 = strVal(field2); + /* Try to identify as a once-qualified column */ node = qualifiedNameToVar(pstate, NULL, name1, name2, true, cref->location); @@ -490,18 +509,29 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref) } case 3: { - char *name1 = strVal(linitial(cref->fields)); - char *name2 = strVal(lsecond(cref->fields)); - char *name3 = strVal(lthird(cref->fields)); + Node *field1 = (Node *) linitial(cref->fields); + Node *field2 = (Node *) lsecond(cref->fields); + Node *field3 = (Node *) lthird(cref->fields); + char *name1; + char *name2; + char *name3; + + Assert(IsA(field1, String)); + name1 = strVal(field1); + Assert(IsA(field2, String)); + name2 = strVal(field2); /* Whole-row reference? */ - if (strcmp(name3, "*") == 0) + if (IsA(field3, A_Star)) { node = transformWholeRowRef(pstate, name1, name2, cref->location); break; } + Assert(IsA(field3, String)); + name3 = strVal(field3); + /* Try to identify as a twice-qualified column */ node = qualifiedNameToVar(pstate, name1, name2, name3, true, cref->location); @@ -520,10 +550,21 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref) } case 4: { - char *name1 = strVal(linitial(cref->fields)); - char *name2 = strVal(lsecond(cref->fields)); - char *name3 = strVal(lthird(cref->fields)); - char *name4 = strVal(lfourth(cref->fields)); + Node *field1 = (Node *) linitial(cref->fields); + Node *field2 = (Node *) lsecond(cref->fields); + Node *field3 = (Node *) lthird(cref->fields); + Node *field4 = (Node *) lfourth(cref->fields); + char *name1; + char *name2; + char *name3; + char *name4; + + Assert(IsA(field1, String)); + name1 = strVal(field1); + Assert(IsA(field2, String)); + name2 = strVal(field2); + Assert(IsA(field3, String)); + name3 = strVal(field3); /* * We check the catalog name and then ignore it. @@ -536,13 +577,16 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref) parser_errposition(pstate, cref->location))); /* Whole-row reference? */ - if (strcmp(name4, "*") == 0) + if (IsA(field4, A_Star)) { node = transformWholeRowRef(pstate, name2, name3, cref->location); break; } + Assert(IsA(field4, String)); + name4 = strVal(field4); + /* Try to identify as a twice-qualified column */ node = qualifiedNameToVar(pstate, name2, name3, name4, true, cref->location); diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c index c7758e9adde..df87f3874cc 100644 --- a/src/backend/parser/parse_target.c +++ b/src/backend/parser/parse_target.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/parser/parse_target.c,v 1.162 2008/08/28 23:09:48 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/parser/parse_target.c,v 1.163 2008/08/30 01:39:14 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -109,14 +109,14 @@ transformTargetList(ParseState *pstate, List *targetlist) /* * Check for "something.*". Depending on the complexity of the - * "something", the star could appear as the last name in ColumnRef, + * "something", the star could appear as the last field in ColumnRef, * or as the last indirection item in A_Indirection. */ if (IsA(res->val, ColumnRef)) { ColumnRef *cref = (ColumnRef *) res->val; - if (strcmp(strVal(llast(cref->fields)), "*") == 0) + if (IsA(llast(cref->fields), A_Star)) { /* It is something.*, expand into multiple items */ p_target = list_concat(p_target, @@ -128,10 +128,8 @@ transformTargetList(ParseState *pstate, List *targetlist) else if (IsA(res->val, A_Indirection)) { A_Indirection *ind = (A_Indirection *) res->val; - Node *lastitem = llast(ind->indirection); - if (IsA(lastitem, String) && - strcmp(strVal(lastitem), "*") == 0) + if (IsA(llast(ind->indirection), A_Star)) { /* It is something.*, expand into multiple items */ p_target = list_concat(p_target, @@ -176,14 +174,14 @@ transformExpressionList(ParseState *pstate, List *exprlist) /* * Check for "something.*". Depending on the complexity of the - * "something", the star could appear as the last name in ColumnRef, + * "something", the star could appear as the last field in ColumnRef, * or as the last indirection item in A_Indirection. */ if (IsA(e, ColumnRef)) { ColumnRef *cref = (ColumnRef *) e; - if (strcmp(strVal(llast(cref->fields)), "*") == 0) + if (IsA(llast(cref->fields), A_Star)) { /* It is something.*, expand into multiple items */ result = list_concat(result, @@ -195,10 +193,8 @@ transformExpressionList(ParseState *pstate, List *exprlist) else if (IsA(e, A_Indirection)) { A_Indirection *ind = (A_Indirection *) e; - Node *lastitem = llast(ind->indirection); - if (IsA(lastitem, String) && - strcmp(strVal(lastitem), "*") == 0) + if (IsA(llast(ind->indirection), A_Star)) { /* It is something.*, expand into multiple items */ result = list_concat(result, @@ -560,6 +556,13 @@ transformAssignmentIndirection(ParseState *pstate, if (((A_Indices *) n)->lidx != NULL) isSlice = true; } + else if (IsA(n, A_Star)) + { + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("row expansion via \"*\" is not supported here"), + parser_errposition(pstate, location))); + } else { FieldStore *fstore; @@ -809,7 +812,7 @@ checkInsertTargets(ParseState *pstate, List *cols, List **attrnos) * ExpandColumnRefStar() * Transforms foo.* into a list of expressions or targetlist entries. * - * This handles the case where '*' appears as the last or only name in a + * This handles the case where '*' appears as the last or only item in a * ColumnRef. The code is shared between the case of foo.* at the top level * in a SELECT target list (where we want TargetEntry nodes in the result) * and foo.* in a ROW() or VALUES() construct (where we want just bare @@ -830,13 +833,9 @@ ExpandColumnRefStar(ParseState *pstate, ColumnRef *cref, * (e.g., SELECT * FROM emp, dept) * * Since the grammar only accepts bare '*' at top level of SELECT, we - * need not handle the targetlist==false case here. However, we must - * test for it because the grammar currently fails to distinguish a - * quoted name "*" from a real asterisk. + * need not handle the targetlist==false case here. */ - if (!targetlist) - elog(ERROR, "invalid use of *"); - + Assert(targetlist); return ExpandAllTables(pstate); } else @@ -1226,7 +1225,7 @@ FigureColnameInternal(Node *node, char **name) { Node *i = lfirst(l); - if (strcmp(strVal(i), "*") != 0) + if (IsA(i, String)) fname = strVal(i); } if (fname) @@ -1242,13 +1241,12 @@ FigureColnameInternal(Node *node, char **name) char *fname = NULL; ListCell *l; - /* find last field name, if any, ignoring "*" */ + /* find last field name, if any, ignoring "*" and subscripts */ foreach(l, ind->indirection) { Node *i = lfirst(l); - if (IsA(i, String) && - strcmp(strVal(i), "*") != 0) + if (IsA(i, String)) fname = strVal(i); } if (fname) diff --git a/src/backend/parser/parse_type.c b/src/backend/parser/parse_type.c index 78e210167dc..7f6f1617456 100644 --- a/src/backend/parser/parse_type.c +++ b/src/backend/parser/parse_type.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/parser/parse_type.c,v 1.97 2008/04/29 20:44:49 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/parser/parse_type.c,v 1.98 2008/08/30 01:39:14 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -305,7 +305,8 @@ typenameTypeMod(ParseState *pstate, const TypeName *typename, Type typ) { ColumnRef *cr = (ColumnRef *) tm; - if (list_length(cr->fields) == 1) + if (list_length(cr->fields) == 1 && + IsA(linitial(cr->fields), String)) cstr = strVal(linitial(cr->fields)); } if (!cstr) |