Fix the raw-parsetree representation of star (as in SELECT * FROM or
authorTom Lane <tgl@sss.pgh.pa.us>
Sat, 30 Aug 2008 01:39:14 +0000 (01:39 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Sat, 30 Aug 2008 01:39:14 +0000 (01:39 +0000)
SELECT foo.*) so that it cannot be confused with a quoted identifier "*".
Instead create a separate node type A_Star to represent this notation.
Per pgsql-hackers discussion of 2007-Sep-27.

13 files changed:
src/backend/catalog/namespace.c
src/backend/commands/async.c
src/backend/nodes/copyfuncs.c
src/backend/nodes/equalfuncs.c
src/backend/nodes/outfuncs.c
src/backend/parser/gram.y
src/backend/parser/parse_clause.c
src/backend/parser/parse_expr.c
src/backend/parser/parse_target.c
src/backend/parser/parse_type.c
src/backend/tcop/utility.c
src/include/nodes/nodes.h
src/include/nodes/parsenodes.h

index 6446ecb6a081148e46d5de8ffcbd11d59fe78b6d..fc3126cb2d59953d8821c03916c3978535c5bc59 100644 (file)
@@ -2189,6 +2189,9 @@ makeRangeVarFromNameList(List *names)
  *
  * This is used primarily to form error messages, and so we do not quote
  * the list elements, for the sake of legibility.
+ *
+ * In most scenarios the list elements should always be Value strings,
+ * but we also allow A_Star for the convenience of ColumnRef processing.
  */
 char *
 NameListToString(List *names)
@@ -2200,9 +2203,18 @@ NameListToString(List *names)
 
        foreach(l, names)
        {
+               Node       *name = (Node *) lfirst(l);
+
                if (l != list_head(names))
                        appendStringInfoChar(&string, '.');
-               appendStringInfoString(&string, strVal(lfirst(l)));
+
+               if (IsA(name, String))
+                       appendStringInfoString(&string, strVal(name));
+               else if (IsA(name, A_Star))
+                       appendStringInfoString(&string, "*");
+               else
+                       elog(ERROR, "unexpected node type in name list: %d",
+                                (int) nodeTag(name));
        }
 
        return string.data;
index 583b34d90f969a8efc74d638b59b5535ac9d49ea..5d26879e6a7b762fc975407d9fb71e9cd373720e 100644 (file)
@@ -274,24 +274,16 @@ Async_Listen(const char *relname)
 void
 Async_Unlisten(const char *relname)
 {
-       /* Handle specially the `unlisten "*"' command */
-       if ((!relname) || (*relname == '\0') || (strcmp(relname, "*") == 0))
-       {
-               Async_UnlistenAll();
-       }
-       else
-       {
-               if (Trace_notify)
-                       elog(DEBUG1, "Async_Unlisten(%s,%d)", relname, MyProcPid);
+       if (Trace_notify)
+               elog(DEBUG1, "Async_Unlisten(%s,%d)", relname, MyProcPid);
 
-               queue_listen(LISTEN_UNLISTEN, relname);
-       }
+       queue_listen(LISTEN_UNLISTEN, relname);
 }
 
 /*
  * Async_UnlistenAll
  *
- *             This is invoked by UNLISTEN "*" command, and also at backend exit.
+ *             This is invoked by UNLISTEN * command, and also at backend exit.
  */
 void
 Async_UnlistenAll(void)
index f0f902c69a644c1003d24c378dce39da677f942e..c173eec08016ddc5f6ffab38a798dc077beee5a6 100644 (file)
@@ -1697,6 +1697,14 @@ _copyFuncCall(FuncCall *from)
        return newnode;
 }
 
+static A_Star *
+_copyAStar(A_Star *from)
+{
+       A_Star  *newnode = makeNode(A_Star);
+
+       return newnode;
+}
+
 static A_Indices *
 _copyAIndices(A_Indices *from)
 {
@@ -3589,6 +3597,9 @@ copyObject(void *from)
                case T_FuncCall:
                        retval = _copyFuncCall(from);
                        break;
+               case T_A_Star:
+                       retval = _copyAStar(from);
+                       break;
                case T_A_Indices:
                        retval = _copyAIndices(from);
                        break;
index 9b9fd46567c21b5736c27ef80f521407667b9de2..028aa4a155faf5cb287e9592144ec2712601d234 100644 (file)
@@ -1765,6 +1765,12 @@ _equalFuncCall(FuncCall *a, FuncCall *b)
        return true;
 }
 
+static bool
+_equalAStar(A_Star *a, A_Star *b)
+{
+       return true;
+}
+
 static bool
 _equalAIndices(A_Indices *a, A_Indices *b)
 {
@@ -2531,6 +2537,9 @@ equal(void *a, void *b)
                case T_FuncCall:
                        retval = _equalFuncCall(a, b);
                        break;
+               case T_A_Star:
+                       retval = _equalAStar(a, b);
+                       break;
                case T_A_Indices:
                        retval = _equalAIndices(a, b);
                        break;
index d8cb3da6e65269c0f3be2c0f33e2770364d9c20b..9dcd3a720330758816772c21346ac92f9d12c77d 100644 (file)
@@ -1989,6 +1989,12 @@ _outAConst(StringInfo str, A_Const *node)
        WRITE_LOCATION_FIELD(location);
 }
 
+static void
+_outA_Star(StringInfo str, A_Star *node)
+{
+       WRITE_NODE_TYPE("A_STAR");
+}
+
 static void
 _outA_Indices(StringInfo str, A_Indices *node)
 {
@@ -2467,6 +2473,9 @@ _outNode(StringInfo str, void *obj)
                        case T_A_Const:
                                _outAConst(str, obj);
                                break;
+                       case T_A_Star:
+                               _outA_Star(str, obj);
+                               break;
                        case T_A_Indices:
                                _outA_Indices(str, obj);
                                break;
index 17a4d24e404f35509da71d65172163e425430600..0af6142f5d4827aa23a0bd9f207adc448dd9f09d 100644 (file)
@@ -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
index e1cf581de27a0dabd53f4aaa46631bfdbdf98210..2c587d68f87447d48bf43a6b33b91aa5df870f7e 100644 (file)
@@ -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;
index a4f5fbf173b90954f653f211d06b4e2185c2d1e4..e6eb675227ae8525b8621b96224674ced4689e36 100644 (file)
@@ -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);
index 29c719002c920dba780ba894495581f0c3c2cd3e..0dfa363185dc6b3676533a2bd3c2aeec5901abb2 100644 (file)
@@ -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)
index 076536133da107e7bb52618498ead4f5eb3c0f46..778dec810444ede8ebc1cddb36f4ad013a7d0f07 100644 (file)
@@ -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)
index b5cba578efc8a16dc1ee7ca5e0e076d61393a2fe..920d605644654dcfeb38485fe776e6b784a631cd 100644 (file)
@@ -817,7 +817,10 @@ ProcessUtility(Node *parsetree,
                        {
                                UnlistenStmt *stmt = (UnlistenStmt *) parsetree;
 
-                               Async_Unlisten(stmt->relation->relname);
+                               if (stmt->relation)
+                                       Async_Unlisten(stmt->relation->relname);
+                               else
+                                       Async_UnlistenAll();
                        }
                        break;
 
index f365eacdbb5105315ce12f696b6ea0dace5be2a3..ad64949900eddfd0702b13eb3a2854be4b7db855 100644 (file)
@@ -324,6 +324,7 @@ typedef enum NodeTag
        T_ParamRef,
        T_A_Const,
        T_FuncCall,
+       T_A_Star,
        T_A_Indices,
        T_A_Indirection,
        T_A_ArrayExpr,
index 2366e0384a0901dde1a4545bcd79e76a6725f077..9f2057b71e9100fb4885571fb4870139e0206127 100644 (file)
@@ -178,8 +178,10 @@ typedef struct TypeName
 /*
  * ColumnRef - specifies a reference to a column, or possibly a whole tuple
  *
- *             The "fields" list must be nonempty; its last component may be "*"
- *             instead of a regular field name.
+ * The "fields" list must be nonempty.  It can contain string Value nodes
+ * (representing names) and A_Star nodes (representing occurrence of a '*').
+ * Currently, A_Star must appear only as the last list element --- the grammar
+ * is responsible for enforcing this!
  *
  * Note: any array subscripting or selection of fields from composite columns
  * is represented by an A_Indirection node above the ColumnRef.  However,
@@ -189,7 +191,7 @@ typedef struct TypeName
 typedef struct ColumnRef
 {
        NodeTag         type;
-       List       *fields;                     /* field names (list of Value strings) */
+       List       *fields;                     /* field names (Value strings) or A_Star */
        int                     location;               /* token location, or -1 if unknown */
 } ColumnRef;
 
@@ -271,35 +273,46 @@ typedef struct FuncCall
 } FuncCall;
 
 /*
- * A_Indices - array reference or bounds ([lidx:uidx] or [uidx])
+ * A_Star - '*' representing all columns of a table or compound field
+ *
+ * This can appear within ColumnRef.fields, A_Indirection.indirection, and
+ * ResTarget.indirection lists.
+ */
+typedef struct A_Star
+{
+       NodeTag         type;
+} A_Star;
+
+/*
+ * A_Indices - array subscript or slice bounds ([lidx:uidx] or [uidx])
  */
 typedef struct A_Indices
 {
        NodeTag         type;
-       Node       *lidx;                       /* could be NULL */
+       Node       *lidx;                       /* NULL if it's a single subscript */
        Node       *uidx;
 } A_Indices;
 
 /*
  * A_Indirection - select a field and/or array element from an expression
  *
- * The indirection list can contain both A_Indices nodes (representing
- * subscripting) and string Value nodes (representing field selection
- * --- the string value is the name of the field to select).  For example,
- * a complex selection operation like
+ * The indirection list can contain A_Indices nodes (representing
+ * subscripting), string Value nodes (representing field selection --- the
+ * string value is the name of the field to select), and A_Star nodes
+ * (representing selection of all fields of a composite type).
+ * For example, a complex selection operation like
  *                             (foo).field1[42][7].field2
  * would be represented with a single A_Indirection node having a 4-element
  * indirection list.
  *
- * Note: as of Postgres 8.0, we don't support arrays of composite values,
- * so cases in which a field select follows a subscript aren't actually
- * semantically legal. However the parser is prepared to handle such.
+ * Currently, A_Star must appear only as the last list element --- the grammar
+ * is responsible for enforcing this!
  */
 typedef struct A_Indirection
 {
        NodeTag         type;
        Node       *arg;                        /* the thing being selected from */
-       List       *indirection;        /* subscripts and/or field names */
+       List       *indirection;        /* subscripts and/or field names and/or * */
 } A_Indirection;
 
 /*
@@ -334,7 +347,7 @@ typedef struct ResTarget
 {
        NodeTag         type;
        char       *name;                       /* column name or NULL */
-       List       *indirection;        /* subscripts and field names, or NIL */
+       List       *indirection;        /* subscripts, field names, and '*', or NIL */
        Node       *val;                        /* the value expression to compute or assign */
        int                     location;               /* token location, or -1 if unknown */
 } ResTarget;
@@ -1739,7 +1752,7 @@ typedef struct NotifyStmt
 typedef struct ListenStmt
 {
        NodeTag         type;
-       RangeVar   *relation;           /* qualified name to listen on */
+       RangeVar   *relation;           /* name to listen on */
 } ListenStmt;
 
 /* ----------------------
@@ -1749,7 +1762,7 @@ typedef struct ListenStmt
 typedef struct UnlistenStmt
 {
        NodeTag         type;
-       RangeVar   *relation;           /* qualified name to unlisten on, or '*' */
+       RangeVar   *relation;           /* name to unlisten on, or NULL for all */
 } UnlistenStmt;
 
 /* ----------------------