~ubuntu-branches/debian/sid/postgresql-9.3/sid

« back to all changes in this revision

Viewing changes to src/backend/parser/parse_target.c

  • Committer: Package Import Robot
  • Author(s): Martin Pitt
  • Date: 2013-05-08 05:39:52 UTC
  • Revision ID: package-import@ubuntu.com-20130508053952-1j7uilp7mjtrvq8q
Tags: upstream-9.3~beta1
ImportĀ upstreamĀ versionĀ 9.3~beta1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*-------------------------------------------------------------------------
 
2
 *
 
3
 * parse_target.c
 
4
 *        handle target lists
 
5
 *
 
6
 * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
 
7
 * Portions Copyright (c) 1994, Regents of the University of California
 
8
 *
 
9
 *
 
10
 * IDENTIFICATION
 
11
 *        src/backend/parser/parse_target.c
 
12
 *
 
13
 *-------------------------------------------------------------------------
 
14
 */
 
15
#include "postgres.h"
 
16
 
 
17
#include "catalog/pg_type.h"
 
18
#include "commands/dbcommands.h"
 
19
#include "funcapi.h"
 
20
#include "miscadmin.h"
 
21
#include "nodes/makefuncs.h"
 
22
#include "nodes/nodeFuncs.h"
 
23
#include "parser/parsetree.h"
 
24
#include "parser/parse_coerce.h"
 
25
#include "parser/parse_expr.h"
 
26
#include "parser/parse_func.h"
 
27
#include "parser/parse_relation.h"
 
28
#include "parser/parse_target.h"
 
29
#include "parser/parse_type.h"
 
30
#include "utils/builtins.h"
 
31
#include "utils/lsyscache.h"
 
32
#include "utils/rel.h"
 
33
#include "utils/typcache.h"
 
34
 
 
35
 
 
36
static void markTargetListOrigin(ParseState *pstate, TargetEntry *tle,
 
37
                                         Var *var, int levelsup);
 
38
static Node *transformAssignmentIndirection(ParseState *pstate,
 
39
                                                           Node *basenode,
 
40
                                                           const char *targetName,
 
41
                                                           bool targetIsArray,
 
42
                                                           Oid targetTypeId,
 
43
                                                           int32 targetTypMod,
 
44
                                                           Oid targetCollation,
 
45
                                                           ListCell *indirection,
 
46
                                                           Node *rhs,
 
47
                                                           int location);
 
48
static Node *transformAssignmentSubscripts(ParseState *pstate,
 
49
                                                          Node *basenode,
 
50
                                                          const char *targetName,
 
51
                                                          Oid targetTypeId,
 
52
                                                          int32 targetTypMod,
 
53
                                                          Oid targetCollation,
 
54
                                                          List *subscripts,
 
55
                                                          bool isSlice,
 
56
                                                          ListCell *next_indirection,
 
57
                                                          Node *rhs,
 
58
                                                          int location);
 
59
static List *ExpandColumnRefStar(ParseState *pstate, ColumnRef *cref,
 
60
                                        bool make_target_entry);
 
61
static List *ExpandAllTables(ParseState *pstate, int location);
 
62
static List *ExpandIndirectionStar(ParseState *pstate, A_Indirection *ind,
 
63
                                          bool make_target_entry, ParseExprKind exprKind);
 
64
static List *ExpandSingleTable(ParseState *pstate, RangeTblEntry *rte,
 
65
                                  int location, bool make_target_entry);
 
66
static List *ExpandRowReference(ParseState *pstate, Node *expr,
 
67
                                   bool make_target_entry);
 
68
static int      FigureColnameInternal(Node *node, char **name);
 
69
 
 
70
 
 
71
/*
 
72
 * transformTargetEntry()
 
73
 *      Transform any ordinary "expression-type" node into a targetlist entry.
 
74
 *      This is exported so that parse_clause.c can generate targetlist entries
 
75
 *      for ORDER/GROUP BY items that are not already in the targetlist.
 
76
 *
 
77
 * node         the (untransformed) parse tree for the value expression.
 
78
 * expr         the transformed expression, or NULL if caller didn't do it yet.
 
79
 * exprKind     expression kind (EXPR_KIND_SELECT_TARGET, etc)
 
80
 * colname      the column name to be assigned, or NULL if none yet set.
 
81
 * resjunk      true if the target should be marked resjunk, ie, it is not
 
82
 *                      wanted in the final projected tuple.
 
83
 */
 
84
TargetEntry *
 
85
transformTargetEntry(ParseState *pstate,
 
86
                                         Node *node,
 
87
                                         Node *expr,
 
88
                                         ParseExprKind exprKind,
 
89
                                         char *colname,
 
90
                                         bool resjunk)
 
91
{
 
92
        /* Transform the node if caller didn't do it already */
 
93
        if (expr == NULL)
 
94
                expr = transformExpr(pstate, node, exprKind);
 
95
 
 
96
        if (colname == NULL && !resjunk)
 
97
        {
 
98
                /*
 
99
                 * Generate a suitable column name for a column without any explicit
 
100
                 * 'AS ColumnName' clause.
 
101
                 */
 
102
                colname = FigureColname(node);
 
103
        }
 
104
 
 
105
        return makeTargetEntry((Expr *) expr,
 
106
                                                   (AttrNumber) pstate->p_next_resno++,
 
107
                                                   colname,
 
108
                                                   resjunk);
 
109
}
 
110
 
 
111
 
 
112
/*
 
113
 * transformTargetList()
 
114
 * Turns a list of ResTarget's into a list of TargetEntry's.
 
115
 *
 
116
 * At this point, we don't care whether we are doing SELECT, UPDATE,
 
117
 * or RETURNING; we just transform the given expressions (the "val" fields).
 
118
 * However, our subroutines care, so we need the exprKind parameter.
 
119
 */
 
120
List *
 
121
transformTargetList(ParseState *pstate, List *targetlist,
 
122
                                        ParseExprKind exprKind)
 
123
{
 
124
        List       *p_target = NIL;
 
125
        ListCell   *o_target;
 
126
 
 
127
        foreach(o_target, targetlist)
 
128
        {
 
129
                ResTarget  *res = (ResTarget *) lfirst(o_target);
 
130
 
 
131
                /*
 
132
                 * Check for "something.*".  Depending on the complexity of the
 
133
                 * "something", the star could appear as the last field in ColumnRef,
 
134
                 * or as the last indirection item in A_Indirection.
 
135
                 */
 
136
                if (IsA(res->val, ColumnRef))
 
137
                {
 
138
                        ColumnRef  *cref = (ColumnRef *) res->val;
 
139
 
 
140
                        if (IsA(llast(cref->fields), A_Star))
 
141
                        {
 
142
                                /* It is something.*, expand into multiple items */
 
143
                                p_target = list_concat(p_target,
 
144
                                                                           ExpandColumnRefStar(pstate, cref,
 
145
                                                                                                                   true));
 
146
                                continue;
 
147
                        }
 
148
                }
 
149
                else if (IsA(res->val, A_Indirection))
 
150
                {
 
151
                        A_Indirection *ind = (A_Indirection *) res->val;
 
152
 
 
153
                        if (IsA(llast(ind->indirection), A_Star))
 
154
                        {
 
155
                                /* It is something.*, expand into multiple items */
 
156
                                p_target = list_concat(p_target,
 
157
                                                                           ExpandIndirectionStar(pstate, ind,
 
158
                                                                                                                         true, exprKind));
 
159
                                continue;
 
160
                        }
 
161
                }
 
162
 
 
163
                /*
 
164
                 * Not "something.*", so transform as a single expression
 
165
                 */
 
166
                p_target = lappend(p_target,
 
167
                                                   transformTargetEntry(pstate,
 
168
                                                                                                res->val,
 
169
                                                                                                NULL,
 
170
                                                                                                exprKind,
 
171
                                                                                                res->name,
 
172
                                                                                                false));
 
173
        }
 
174
 
 
175
        return p_target;
 
176
}
 
177
 
 
178
 
 
179
/*
 
180
 * transformExpressionList()
 
181
 *
 
182
 * This is the identical transformation to transformTargetList, except that
 
183
 * the input list elements are bare expressions without ResTarget decoration,
 
184
 * and the output elements are likewise just expressions without TargetEntry
 
185
 * decoration.  We use this for ROW() and VALUES() constructs.
 
186
 */
 
187
List *
 
188
transformExpressionList(ParseState *pstate, List *exprlist,
 
189
                                                ParseExprKind exprKind)
 
190
{
 
191
        List       *result = NIL;
 
192
        ListCell   *lc;
 
193
 
 
194
        foreach(lc, exprlist)
 
195
        {
 
196
                Node       *e = (Node *) lfirst(lc);
 
197
 
 
198
                /*
 
199
                 * Check for "something.*".  Depending on the complexity of the
 
200
                 * "something", the star could appear as the last field in ColumnRef,
 
201
                 * or as the last indirection item in A_Indirection.
 
202
                 */
 
203
                if (IsA(e, ColumnRef))
 
204
                {
 
205
                        ColumnRef  *cref = (ColumnRef *) e;
 
206
 
 
207
                        if (IsA(llast(cref->fields), A_Star))
 
208
                        {
 
209
                                /* It is something.*, expand into multiple items */
 
210
                                result = list_concat(result,
 
211
                                                                         ExpandColumnRefStar(pstate, cref,
 
212
                                                                                                                 false));
 
213
                                continue;
 
214
                        }
 
215
                }
 
216
                else if (IsA(e, A_Indirection))
 
217
                {
 
218
                        A_Indirection *ind = (A_Indirection *) e;
 
219
 
 
220
                        if (IsA(llast(ind->indirection), A_Star))
 
221
                        {
 
222
                                /* It is something.*, expand into multiple items */
 
223
                                result = list_concat(result,
 
224
                                                                         ExpandIndirectionStar(pstate, ind,
 
225
                                                                                                                   false, exprKind));
 
226
                                continue;
 
227
                        }
 
228
                }
 
229
 
 
230
                /*
 
231
                 * Not "something.*", so transform as a single expression
 
232
                 */
 
233
                result = lappend(result,
 
234
                                                 transformExpr(pstate, e, exprKind));
 
235
        }
 
236
 
 
237
        return result;
 
238
}
 
239
 
 
240
 
 
241
/*
 
242
 * markTargetListOrigins()
 
243
 *              Mark targetlist columns that are simple Vars with the source
 
244
 *              table's OID and column number.
 
245
 *
 
246
 * Currently, this is done only for SELECT targetlists, since we only
 
247
 * need the info if we are going to send it to the frontend.
 
248
 */
 
249
void
 
250
markTargetListOrigins(ParseState *pstate, List *targetlist)
 
251
{
 
252
        ListCell   *l;
 
253
 
 
254
        foreach(l, targetlist)
 
255
        {
 
256
                TargetEntry *tle = (TargetEntry *) lfirst(l);
 
257
 
 
258
                markTargetListOrigin(pstate, tle, (Var *) tle->expr, 0);
 
259
        }
 
260
}
 
261
 
 
262
/*
 
263
 * markTargetListOrigin()
 
264
 *              If 'var' is a Var of a plain relation, mark 'tle' with its origin
 
265
 *
 
266
 * levelsup is an extra offset to interpret the Var's varlevelsup correctly.
 
267
 *
 
268
 * This is split out so it can recurse for join references.  Note that we
 
269
 * do not drill down into views, but report the view as the column owner.
 
270
 */
 
271
static void
 
272
markTargetListOrigin(ParseState *pstate, TargetEntry *tle,
 
273
                                         Var *var, int levelsup)
 
274
{
 
275
        int                     netlevelsup;
 
276
        RangeTblEntry *rte;
 
277
        AttrNumber      attnum;
 
278
 
 
279
        if (var == NULL || !IsA(var, Var))
 
280
                return;
 
281
        netlevelsup = var->varlevelsup + levelsup;
 
282
        rte = GetRTEByRangeTablePosn(pstate, var->varno, netlevelsup);
 
283
        attnum = var->varattno;
 
284
 
 
285
        switch (rte->rtekind)
 
286
        {
 
287
                case RTE_RELATION:
 
288
                        /* It's a table or view, report it */
 
289
                        tle->resorigtbl = rte->relid;
 
290
                        tle->resorigcol = attnum;
 
291
                        break;
 
292
                case RTE_SUBQUERY:
 
293
                        /* Subselect-in-FROM: copy up from the subselect */
 
294
                        if (attnum != InvalidAttrNumber)
 
295
                        {
 
296
                                TargetEntry *ste = get_tle_by_resno(rte->subquery->targetList,
 
297
                                                                                                        attnum);
 
298
 
 
299
                                if (ste == NULL || ste->resjunk)
 
300
                                        elog(ERROR, "subquery %s does not have attribute %d",
 
301
                                                 rte->eref->aliasname, attnum);
 
302
                                tle->resorigtbl = ste->resorigtbl;
 
303
                                tle->resorigcol = ste->resorigcol;
 
304
                        }
 
305
                        break;
 
306
                case RTE_JOIN:
 
307
                        /* Join RTE --- recursively inspect the alias variable */
 
308
                        if (attnum != InvalidAttrNumber)
 
309
                        {
 
310
                                Var                *aliasvar;
 
311
 
 
312
                                Assert(attnum > 0 && attnum <= list_length(rte->joinaliasvars));
 
313
                                aliasvar = (Var *) list_nth(rte->joinaliasvars, attnum - 1);
 
314
                                markTargetListOrigin(pstate, tle, aliasvar, netlevelsup);
 
315
                        }
 
316
                        break;
 
317
                case RTE_FUNCTION:
 
318
                case RTE_VALUES:
 
319
                        /* not a simple relation, leave it unmarked */
 
320
                        break;
 
321
                case RTE_CTE:
 
322
 
 
323
                        /*
 
324
                         * CTE reference: copy up from the subquery, if possible. If the
 
325
                         * RTE is a recursive self-reference then we can't do anything
 
326
                         * because we haven't finished analyzing it yet. However, it's no
 
327
                         * big loss because we must be down inside the recursive term of a
 
328
                         * recursive CTE, and so any markings on the current targetlist
 
329
                         * are not going to affect the results anyway.
 
330
                         */
 
331
                        if (attnum != InvalidAttrNumber && !rte->self_reference)
 
332
                        {
 
333
                                CommonTableExpr *cte = GetCTEForRTE(pstate, rte, netlevelsup);
 
334
                                TargetEntry *ste;
 
335
 
 
336
                                ste = get_tle_by_resno(GetCTETargetList(cte), attnum);
 
337
                                if (ste == NULL || ste->resjunk)
 
338
                                        elog(ERROR, "subquery %s does not have attribute %d",
 
339
                                                 rte->eref->aliasname, attnum);
 
340
                                tle->resorigtbl = ste->resorigtbl;
 
341
                                tle->resorigcol = ste->resorigcol;
 
342
                        }
 
343
                        break;
 
344
        }
 
345
}
 
346
 
 
347
 
 
348
/*
 
349
 * transformAssignedExpr()
 
350
 *      This is used in INSERT and UPDATE statements only.      It prepares an
 
351
 *      expression for assignment to a column of the target table.
 
352
 *      This includes coercing the given value to the target column's type
 
353
 *      (if necessary), and dealing with any subfield names or subscripts
 
354
 *      attached to the target column itself.  The input expression has
 
355
 *      already been through transformExpr().
 
356
 *
 
357
 * pstate               parse state
 
358
 * expr                 expression to be modified
 
359
 * exprKind             indicates which type of statement we're dealing with
 
360
 * colname              target column name (ie, name of attribute to be assigned to)
 
361
 * attrno               target attribute number
 
362
 * indirection  subscripts/field names for target column, if any
 
363
 * location             error cursor position for the target column, or -1
 
364
 *
 
365
 * Returns the modified expression.
 
366
 *
 
367
 * Note: location points at the target column name (SET target or INSERT
 
368
 * column name list entry), and must therefore be -1 in an INSERT that
 
369
 * omits the column name list.  So we should usually prefer to use
 
370
 * exprLocation(expr) for errors that can happen in a default INSERT.
 
371
 */
 
372
Expr *
 
373
transformAssignedExpr(ParseState *pstate,
 
374
                                          Expr *expr,
 
375
                                          ParseExprKind exprKind,
 
376
                                          char *colname,
 
377
                                          int attrno,
 
378
                                          List *indirection,
 
379
                                          int location)
 
380
{
 
381
        Relation        rd = pstate->p_target_relation;
 
382
        Oid                     type_id;                /* type of value provided */
 
383
        Oid                     attrtype;               /* type of target column */
 
384
        int32           attrtypmod;
 
385
        Oid                     attrcollation;  /* collation of target column */
 
386
        ParseExprKind sv_expr_kind;
 
387
 
 
388
        /*
 
389
         * Save and restore identity of expression type we're parsing.  We must
 
390
         * set p_expr_kind here because we can parse subscripts without going
 
391
         * through transformExpr().
 
392
         */
 
393
        Assert(exprKind != EXPR_KIND_NONE);
 
394
        sv_expr_kind = pstate->p_expr_kind;
 
395
        pstate->p_expr_kind = exprKind;
 
396
 
 
397
        Assert(rd != NULL);
 
398
        if (attrno <= 0)
 
399
                ereport(ERROR,
 
400
                                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 
401
                                 errmsg("cannot assign to system column \"%s\"",
 
402
                                                colname),
 
403
                                 parser_errposition(pstate, location)));
 
404
        attrtype = attnumTypeId(rd, attrno);
 
405
        attrtypmod = rd->rd_att->attrs[attrno - 1]->atttypmod;
 
406
        attrcollation = rd->rd_att->attrs[attrno - 1]->attcollation;
 
407
 
 
408
        /*
 
409
         * If the expression is a DEFAULT placeholder, insert the attribute's
 
410
         * type/typmod/collation into it so that exprType etc will report the
 
411
         * right things.  (We expect that the eventually substituted default
 
412
         * expression will in fact have this type and typmod.  The collation
 
413
         * likely doesn't matter, but let's set it correctly anyway.)  Also,
 
414
         * reject trying to update a subfield or array element with DEFAULT, since
 
415
         * there can't be any default for portions of a column.
 
416
         */
 
417
        if (expr && IsA(expr, SetToDefault))
 
418
        {
 
419
                SetToDefault *def = (SetToDefault *) expr;
 
420
 
 
421
                def->typeId = attrtype;
 
422
                def->typeMod = attrtypmod;
 
423
                def->collation = attrcollation;
 
424
                if (indirection)
 
425
                {
 
426
                        if (IsA(linitial(indirection), A_Indices))
 
427
                                ereport(ERROR,
 
428
                                                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 
429
                                                 errmsg("cannot set an array element to DEFAULT"),
 
430
                                                 parser_errposition(pstate, location)));
 
431
                        else
 
432
                                ereport(ERROR,
 
433
                                                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 
434
                                                 errmsg("cannot set a subfield to DEFAULT"),
 
435
                                                 parser_errposition(pstate, location)));
 
436
                }
 
437
        }
 
438
 
 
439
        /* Now we can use exprType() safely. */
 
440
        type_id = exprType((Node *) expr);
 
441
 
 
442
        /*
 
443
         * If there is indirection on the target column, prepare an array or
 
444
         * subfield assignment expression.      This will generate a new column value
 
445
         * that the source value has been inserted into, which can then be placed
 
446
         * in the new tuple constructed by INSERT or UPDATE.
 
447
         */
 
448
        if (indirection)
 
449
        {
 
450
                Node       *colVar;
 
451
 
 
452
                if (pstate->p_is_insert)
 
453
                {
 
454
                        /*
 
455
                         * The command is INSERT INTO table (col.something) ... so there
 
456
                         * is not really a source value to work with. Insert a NULL
 
457
                         * constant as the source value.
 
458
                         */
 
459
                        colVar = (Node *) makeNullConst(attrtype, attrtypmod,
 
460
                                                                                        attrcollation);
 
461
                }
 
462
                else
 
463
                {
 
464
                        /*
 
465
                         * Build a Var for the column to be updated.
 
466
                         */
 
467
                        colVar = (Node *) make_var(pstate,
 
468
                                                                           pstate->p_target_rangetblentry,
 
469
                                                                           attrno,
 
470
                                                                           location);
 
471
                }
 
472
 
 
473
                expr = (Expr *)
 
474
                        transformAssignmentIndirection(pstate,
 
475
                                                                                   colVar,
 
476
                                                                                   colname,
 
477
                                                                                   false,
 
478
                                                                                   attrtype,
 
479
                                                                                   attrtypmod,
 
480
                                                                                   attrcollation,
 
481
                                                                                   list_head(indirection),
 
482
                                                                                   (Node *) expr,
 
483
                                                                                   location);
 
484
        }
 
485
        else
 
486
        {
 
487
                /*
 
488
                 * For normal non-qualified target column, do type checking and
 
489
                 * coercion.
 
490
                 */
 
491
                Node       *orig_expr = (Node *) expr;
 
492
 
 
493
                expr = (Expr *)
 
494
                        coerce_to_target_type(pstate,
 
495
                                                                  orig_expr, type_id,
 
496
                                                                  attrtype, attrtypmod,
 
497
                                                                  COERCION_ASSIGNMENT,
 
498
                                                                  COERCE_IMPLICIT_CAST,
 
499
                                                                  -1);
 
500
                if (expr == NULL)
 
501
                        ereport(ERROR,
 
502
                                        (errcode(ERRCODE_DATATYPE_MISMATCH),
 
503
                                         errmsg("column \"%s\" is of type %s"
 
504
                                                        " but expression is of type %s",
 
505
                                                        colname,
 
506
                                                        format_type_be(attrtype),
 
507
                                                        format_type_be(type_id)),
 
508
                                 errhint("You will need to rewrite or cast the expression."),
 
509
                                         parser_errposition(pstate, exprLocation(orig_expr))));
 
510
        }
 
511
 
 
512
        pstate->p_expr_kind = sv_expr_kind;
 
513
 
 
514
        return expr;
 
515
}
 
516
 
 
517
 
 
518
/*
 
519
 * updateTargetListEntry()
 
520
 *      This is used in UPDATE statements only. It prepares an UPDATE
 
521
 *      TargetEntry for assignment to a column of the target table.
 
522
 *      This includes coercing the given value to the target column's type
 
523
 *      (if necessary), and dealing with any subfield names or subscripts
 
524
 *      attached to the target column itself.
 
525
 *
 
526
 * pstate               parse state
 
527
 * tle                  target list entry to be modified
 
528
 * colname              target column name (ie, name of attribute to be assigned to)
 
529
 * attrno               target attribute number
 
530
 * indirection  subscripts/field names for target column, if any
 
531
 * location             error cursor position (should point at column name), or -1
 
532
 */
 
533
void
 
534
updateTargetListEntry(ParseState *pstate,
 
535
                                          TargetEntry *tle,
 
536
                                          char *colname,
 
537
                                          int attrno,
 
538
                                          List *indirection,
 
539
                                          int location)
 
540
{
 
541
        /* Fix up expression as needed */
 
542
        tle->expr = transformAssignedExpr(pstate,
 
543
                                                                          tle->expr,
 
544
                                                                          EXPR_KIND_UPDATE_TARGET,
 
545
                                                                          colname,
 
546
                                                                          attrno,
 
547
                                                                          indirection,
 
548
                                                                          location);
 
549
 
 
550
        /*
 
551
         * Set the resno to identify the target column --- the rewriter and
 
552
         * planner depend on this.      We also set the resname to identify the target
 
553
         * column, but this is only for debugging purposes; it should not be
 
554
         * relied on.  (In particular, it might be out of date in a stored rule.)
 
555
         */
 
556
        tle->resno = (AttrNumber) attrno;
 
557
        tle->resname = colname;
 
558
}
 
559
 
 
560
 
 
561
/*
 
562
 * Process indirection (field selection or subscripting) of the target
 
563
 * column in INSERT/UPDATE.  This routine recurses for multiple levels
 
564
 * of indirection --- but note that several adjacent A_Indices nodes in
 
565
 * the indirection list are treated as a single multidimensional subscript
 
566
 * operation.
 
567
 *
 
568
 * In the initial call, basenode is a Var for the target column in UPDATE,
 
569
 * or a null Const of the target's type in INSERT.  In recursive calls,
 
570
 * basenode is NULL, indicating that a substitute node should be consed up if
 
571
 * needed.
 
572
 *
 
573
 * targetName is the name of the field or subfield we're assigning to, and
 
574
 * targetIsArray is true if we're subscripting it.  These are just for
 
575
 * error reporting.
 
576
 *
 
577
 * targetTypeId, targetTypMod, targetCollation indicate the datatype and
 
578
 * collation of the object to be assigned to (initially the target column,
 
579
 * later some subobject).
 
580
 *
 
581
 * indirection is the sublist remaining to process.  When it's NULL, we're
 
582
 * done recursing and can just coerce and return the RHS.
 
583
 *
 
584
 * rhs is the already-transformed value to be assigned; note it has not been
 
585
 * coerced to any particular type.
 
586
 *
 
587
 * location is the cursor error position for any errors.  (Note: this points
 
588
 * to the head of the target clause, eg "foo" in "foo.bar[baz]".  Later we
 
589
 * might want to decorate indirection cells with their own location info,
 
590
 * in which case the location argument could probably be dropped.)
 
591
 */
 
592
static Node *
 
593
transformAssignmentIndirection(ParseState *pstate,
 
594
                                                           Node *basenode,
 
595
                                                           const char *targetName,
 
596
                                                           bool targetIsArray,
 
597
                                                           Oid targetTypeId,
 
598
                                                           int32 targetTypMod,
 
599
                                                           Oid targetCollation,
 
600
                                                           ListCell *indirection,
 
601
                                                           Node *rhs,
 
602
                                                           int location)
 
603
{
 
604
        Node       *result;
 
605
        List       *subscripts = NIL;
 
606
        bool            isSlice = false;
 
607
        ListCell   *i;
 
608
 
 
609
        if (indirection && !basenode)
 
610
        {
 
611
                /* Set up a substitution.  We reuse CaseTestExpr for this. */
 
612
                CaseTestExpr *ctest = makeNode(CaseTestExpr);
 
613
 
 
614
                ctest->typeId = targetTypeId;
 
615
                ctest->typeMod = targetTypMod;
 
616
                ctest->collation = targetCollation;
 
617
                basenode = (Node *) ctest;
 
618
        }
 
619
 
 
620
        /*
 
621
         * We have to split any field-selection operations apart from
 
622
         * subscripting.  Adjacent A_Indices nodes have to be treated as a single
 
623
         * multidimensional subscript operation.
 
624
         */
 
625
        for_each_cell(i, indirection)
 
626
        {
 
627
                Node       *n = lfirst(i);
 
628
 
 
629
                if (IsA(n, A_Indices))
 
630
                {
 
631
                        subscripts = lappend(subscripts, n);
 
632
                        if (((A_Indices *) n)->lidx != NULL)
 
633
                                isSlice = true;
 
634
                }
 
635
                else if (IsA(n, A_Star))
 
636
                {
 
637
                        ereport(ERROR,
 
638
                                        (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 
639
                                         errmsg("row expansion via \"*\" is not supported here"),
 
640
                                         parser_errposition(pstate, location)));
 
641
                }
 
642
                else
 
643
                {
 
644
                        FieldStore *fstore;
 
645
                        Oid                     typrelid;
 
646
                        AttrNumber      attnum;
 
647
                        Oid                     fieldTypeId;
 
648
                        int32           fieldTypMod;
 
649
                        Oid                     fieldCollation;
 
650
 
 
651
                        Assert(IsA(n, String));
 
652
 
 
653
                        /* process subscripts before this field selection */
 
654
                        if (subscripts)
 
655
                        {
 
656
                                /* recurse, and then return because we're done */
 
657
                                return transformAssignmentSubscripts(pstate,
 
658
                                                                                                         basenode,
 
659
                                                                                                         targetName,
 
660
                                                                                                         targetTypeId,
 
661
                                                                                                         targetTypMod,
 
662
                                                                                                         targetCollation,
 
663
                                                                                                         subscripts,
 
664
                                                                                                         isSlice,
 
665
                                                                                                         i,
 
666
                                                                                                         rhs,
 
667
                                                                                                         location);
 
668
                        }
 
669
 
 
670
                        /* No subscripts, so can process field selection here */
 
671
 
 
672
                        typrelid = typeidTypeRelid(targetTypeId);
 
673
                        if (!typrelid)
 
674
                                ereport(ERROR,
 
675
                                                (errcode(ERRCODE_DATATYPE_MISMATCH),
 
676
                                                 errmsg("cannot assign to field \"%s\" of column \"%s\" because its type %s is not a composite type",
 
677
                                                                strVal(n), targetName,
 
678
                                                                format_type_be(targetTypeId)),
 
679
                                                 parser_errposition(pstate, location)));
 
680
 
 
681
                        attnum = get_attnum(typrelid, strVal(n));
 
682
                        if (attnum == InvalidAttrNumber)
 
683
                                ereport(ERROR,
 
684
                                                (errcode(ERRCODE_UNDEFINED_COLUMN),
 
685
                                                 errmsg("cannot assign to field \"%s\" of column \"%s\" because there is no such column in data type %s",
 
686
                                                                strVal(n), targetName,
 
687
                                                                format_type_be(targetTypeId)),
 
688
                                                 parser_errposition(pstate, location)));
 
689
                        if (attnum < 0)
 
690
                                ereport(ERROR,
 
691
                                                (errcode(ERRCODE_UNDEFINED_COLUMN),
 
692
                                                 errmsg("cannot assign to system column \"%s\"",
 
693
                                                                strVal(n)),
 
694
                                                 parser_errposition(pstate, location)));
 
695
 
 
696
                        get_atttypetypmodcoll(typrelid, attnum,
 
697
                                                                &fieldTypeId, &fieldTypMod, &fieldCollation);
 
698
 
 
699
                        /* recurse to create appropriate RHS for field assign */
 
700
                        rhs = transformAssignmentIndirection(pstate,
 
701
                                                                                                 NULL,
 
702
                                                                                                 strVal(n),
 
703
                                                                                                 false,
 
704
                                                                                                 fieldTypeId,
 
705
                                                                                                 fieldTypMod,
 
706
                                                                                                 fieldCollation,
 
707
                                                                                                 lnext(i),
 
708
                                                                                                 rhs,
 
709
                                                                                                 location);
 
710
 
 
711
                        /* and build a FieldStore node */
 
712
                        fstore = makeNode(FieldStore);
 
713
                        fstore->arg = (Expr *) basenode;
 
714
                        fstore->newvals = list_make1(rhs);
 
715
                        fstore->fieldnums = list_make1_int(attnum);
 
716
                        fstore->resulttype = targetTypeId;
 
717
 
 
718
                        return (Node *) fstore;
 
719
                }
 
720
        }
 
721
 
 
722
        /* process trailing subscripts, if any */
 
723
        if (subscripts)
 
724
        {
 
725
                /* recurse, and then return because we're done */
 
726
                return transformAssignmentSubscripts(pstate,
 
727
                                                                                         basenode,
 
728
                                                                                         targetName,
 
729
                                                                                         targetTypeId,
 
730
                                                                                         targetTypMod,
 
731
                                                                                         targetCollation,
 
732
                                                                                         subscripts,
 
733
                                                                                         isSlice,
 
734
                                                                                         NULL,
 
735
                                                                                         rhs,
 
736
                                                                                         location);
 
737
        }
 
738
 
 
739
        /* base case: just coerce RHS to match target type ID */
 
740
 
 
741
        result = coerce_to_target_type(pstate,
 
742
                                                                   rhs, exprType(rhs),
 
743
                                                                   targetTypeId, targetTypMod,
 
744
                                                                   COERCION_ASSIGNMENT,
 
745
                                                                   COERCE_IMPLICIT_CAST,
 
746
                                                                   -1);
 
747
        if (result == NULL)
 
748
        {
 
749
                if (targetIsArray)
 
750
                        ereport(ERROR,
 
751
                                        (errcode(ERRCODE_DATATYPE_MISMATCH),
 
752
                                         errmsg("array assignment to \"%s\" requires type %s"
 
753
                                                        " but expression is of type %s",
 
754
                                                        targetName,
 
755
                                                        format_type_be(targetTypeId),
 
756
                                                        format_type_be(exprType(rhs))),
 
757
                                 errhint("You will need to rewrite or cast the expression."),
 
758
                                         parser_errposition(pstate, location)));
 
759
                else
 
760
                        ereport(ERROR,
 
761
                                        (errcode(ERRCODE_DATATYPE_MISMATCH),
 
762
                                         errmsg("subfield \"%s\" is of type %s"
 
763
                                                        " but expression is of type %s",
 
764
                                                        targetName,
 
765
                                                        format_type_be(targetTypeId),
 
766
                                                        format_type_be(exprType(rhs))),
 
767
                                 errhint("You will need to rewrite or cast the expression."),
 
768
                                         parser_errposition(pstate, location)));
 
769
        }
 
770
 
 
771
        return result;
 
772
}
 
773
 
 
774
/*
 
775
 * helper for transformAssignmentIndirection: process array assignment
 
776
 */
 
777
static Node *
 
778
transformAssignmentSubscripts(ParseState *pstate,
 
779
                                                          Node *basenode,
 
780
                                                          const char *targetName,
 
781
                                                          Oid targetTypeId,
 
782
                                                          int32 targetTypMod,
 
783
                                                          Oid targetCollation,
 
784
                                                          List *subscripts,
 
785
                                                          bool isSlice,
 
786
                                                          ListCell *next_indirection,
 
787
                                                          Node *rhs,
 
788
                                                          int location)
 
789
{
 
790
        Node       *result;
 
791
        Oid                     arrayType;
 
792
        int32           arrayTypMod;
 
793
        Oid                     elementTypeId;
 
794
        Oid                     typeNeeded;
 
795
        Oid                     collationNeeded;
 
796
 
 
797
        Assert(subscripts != NIL);
 
798
 
 
799
        /* Identify the actual array type and element type involved */
 
800
        arrayType = targetTypeId;
 
801
        arrayTypMod = targetTypMod;
 
802
        elementTypeId = transformArrayType(&arrayType, &arrayTypMod);
 
803
 
 
804
        /* Identify type that RHS must provide */
 
805
        typeNeeded = isSlice ? arrayType : elementTypeId;
 
806
 
 
807
        /*
 
808
         * Array normally has same collation as elements, but there's an
 
809
         * exception: we might be subscripting a domain over an array type. In
 
810
         * that case use collation of the base type.
 
811
         */
 
812
        if (arrayType == targetTypeId)
 
813
                collationNeeded = targetCollation;
 
814
        else
 
815
                collationNeeded = get_typcollation(arrayType);
 
816
 
 
817
        /* recurse to create appropriate RHS for array assign */
 
818
        rhs = transformAssignmentIndirection(pstate,
 
819
                                                                                 NULL,
 
820
                                                                                 targetName,
 
821
                                                                                 true,
 
822
                                                                                 typeNeeded,
 
823
                                                                                 arrayTypMod,
 
824
                                                                                 collationNeeded,
 
825
                                                                                 next_indirection,
 
826
                                                                                 rhs,
 
827
                                                                                 location);
 
828
 
 
829
        /* process subscripts */
 
830
        result = (Node *) transformArraySubscripts(pstate,
 
831
                                                                                           basenode,
 
832
                                                                                           arrayType,
 
833
                                                                                           elementTypeId,
 
834
                                                                                           arrayTypMod,
 
835
                                                                                           subscripts,
 
836
                                                                                           rhs);
 
837
 
 
838
        /* If target was a domain over array, need to coerce up to the domain */
 
839
        if (arrayType != targetTypeId)
 
840
        {
 
841
                result = coerce_to_target_type(pstate,
 
842
                                                                           result, exprType(result),
 
843
                                                                           targetTypeId, targetTypMod,
 
844
                                                                           COERCION_ASSIGNMENT,
 
845
                                                                           COERCE_IMPLICIT_CAST,
 
846
                                                                           -1);
 
847
                /* probably shouldn't fail, but check */
 
848
                if (result == NULL)
 
849
                        ereport(ERROR,
 
850
                                        (errcode(ERRCODE_CANNOT_COERCE),
 
851
                                         errmsg("cannot cast type %s to %s",
 
852
                                                        format_type_be(exprType(result)),
 
853
                                                        format_type_be(targetTypeId)),
 
854
                                         parser_errposition(pstate, location)));
 
855
        }
 
856
 
 
857
        return result;
 
858
}
 
859
 
 
860
 
 
861
/*
 
862
 * checkInsertTargets -
 
863
 *        generate a list of INSERT column targets if not supplied, or
 
864
 *        test supplied column names to make sure they are in target table.
 
865
 *        Also return an integer list of the columns' attribute numbers.
 
866
 */
 
867
List *
 
868
checkInsertTargets(ParseState *pstate, List *cols, List **attrnos)
 
869
{
 
870
        *attrnos = NIL;
 
871
 
 
872
        if (cols == NIL)
 
873
        {
 
874
                /*
 
875
                 * Generate default column list for INSERT.
 
876
                 */
 
877
                Form_pg_attribute *attr = pstate->p_target_relation->rd_att->attrs;
 
878
                int                     numcol = pstate->p_target_relation->rd_rel->relnatts;
 
879
                int                     i;
 
880
 
 
881
                for (i = 0; i < numcol; i++)
 
882
                {
 
883
                        ResTarget  *col;
 
884
 
 
885
                        if (attr[i]->attisdropped)
 
886
                                continue;
 
887
 
 
888
                        col = makeNode(ResTarget);
 
889
                        col->name = pstrdup(NameStr(attr[i]->attname));
 
890
                        col->indirection = NIL;
 
891
                        col->val = NULL;
 
892
                        col->location = -1;
 
893
                        cols = lappend(cols, col);
 
894
                        *attrnos = lappend_int(*attrnos, i + 1);
 
895
                }
 
896
        }
 
897
        else
 
898
        {
 
899
                /*
 
900
                 * Do initial validation of user-supplied INSERT column list.
 
901
                 */
 
902
                Bitmapset  *wholecols = NULL;
 
903
                Bitmapset  *partialcols = NULL;
 
904
                ListCell   *tl;
 
905
 
 
906
                foreach(tl, cols)
 
907
                {
 
908
                        ResTarget  *col = (ResTarget *) lfirst(tl);
 
909
                        char       *name = col->name;
 
910
                        int                     attrno;
 
911
 
 
912
                        /* Lookup column name, ereport on failure */
 
913
                        attrno = attnameAttNum(pstate->p_target_relation, name, false);
 
914
                        if (attrno == InvalidAttrNumber)
 
915
                                ereport(ERROR,
 
916
                                                (errcode(ERRCODE_UNDEFINED_COLUMN),
 
917
                                        errmsg("column \"%s\" of relation \"%s\" does not exist",
 
918
                                                   name,
 
919
                                                 RelationGetRelationName(pstate->p_target_relation)),
 
920
                                                 parser_errposition(pstate, col->location)));
 
921
 
 
922
                        /*
 
923
                         * Check for duplicates, but only of whole columns --- we allow
 
924
                         * INSERT INTO foo (col.subcol1, col.subcol2)
 
925
                         */
 
926
                        if (col->indirection == NIL)
 
927
                        {
 
928
                                /* whole column; must not have any other assignment */
 
929
                                if (bms_is_member(attrno, wholecols) ||
 
930
                                        bms_is_member(attrno, partialcols))
 
931
                                        ereport(ERROR,
 
932
                                                        (errcode(ERRCODE_DUPLICATE_COLUMN),
 
933
                                                         errmsg("column \"%s\" specified more than once",
 
934
                                                                        name),
 
935
                                                         parser_errposition(pstate, col->location)));
 
936
                                wholecols = bms_add_member(wholecols, attrno);
 
937
                        }
 
938
                        else
 
939
                        {
 
940
                                /* partial column; must not have any whole assignment */
 
941
                                if (bms_is_member(attrno, wholecols))
 
942
                                        ereport(ERROR,
 
943
                                                        (errcode(ERRCODE_DUPLICATE_COLUMN),
 
944
                                                         errmsg("column \"%s\" specified more than once",
 
945
                                                                        name),
 
946
                                                         parser_errposition(pstate, col->location)));
 
947
                                partialcols = bms_add_member(partialcols, attrno);
 
948
                        }
 
949
 
 
950
                        *attrnos = lappend_int(*attrnos, attrno);
 
951
                }
 
952
        }
 
953
 
 
954
        return cols;
 
955
}
 
956
 
 
957
/*
 
958
 * ExpandColumnRefStar()
 
959
 *              Transforms foo.* into a list of expressions or targetlist entries.
 
960
 *
 
961
 * This handles the case where '*' appears as the last or only item in a
 
962
 * ColumnRef.  The code is shared between the case of foo.* at the top level
 
963
 * in a SELECT target list (where we want TargetEntry nodes in the result)
 
964
 * and foo.* in a ROW() or VALUES() construct (where we want just bare
 
965
 * expressions).
 
966
 *
 
967
 * The referenced columns are marked as requiring SELECT access.
 
968
 */
 
969
static List *
 
970
ExpandColumnRefStar(ParseState *pstate, ColumnRef *cref,
 
971
                                        bool make_target_entry)
 
972
{
 
973
        List       *fields = cref->fields;
 
974
        int                     numnames = list_length(fields);
 
975
 
 
976
        if (numnames == 1)
 
977
        {
 
978
                /*
 
979
                 * Target item is a bare '*', expand all tables
 
980
                 *
 
981
                 * (e.g., SELECT * FROM emp, dept)
 
982
                 *
 
983
                 * Since the grammar only accepts bare '*' at top level of SELECT, we
 
984
                 * need not handle the make_target_entry==false case here.
 
985
                 */
 
986
                Assert(make_target_entry);
 
987
                return ExpandAllTables(pstate, cref->location);
 
988
        }
 
989
        else
 
990
        {
 
991
                /*
 
992
                 * Target item is relation.*, expand that table
 
993
                 *
 
994
                 * (e.g., SELECT emp.*, dname FROM emp, dept)
 
995
                 *
 
996
                 * Note: this code is a lot like transformColumnRef; it's tempting to
 
997
                 * call that instead and then replace the resulting whole-row Var with
 
998
                 * a list of Vars.      However, that would leave us with the RTE's
 
999
                 * selectedCols bitmap showing the whole row as needing select
 
1000
                 * permission, as well as the individual columns.  That would be
 
1001
                 * incorrect (since columns added later shouldn't need select
 
1002
                 * permissions).  We could try to remove the whole-row permission bit
 
1003
                 * after the fact, but duplicating code is less messy.
 
1004
                 */
 
1005
                char       *nspname = NULL;
 
1006
                char       *relname = NULL;
 
1007
                RangeTblEntry *rte = NULL;
 
1008
                int                     levels_up;
 
1009
                enum
 
1010
                {
 
1011
                        CRSERR_NO_RTE,
 
1012
                        CRSERR_WRONG_DB,
 
1013
                        CRSERR_TOO_MANY
 
1014
                }                       crserr = CRSERR_NO_RTE;
 
1015
 
 
1016
                /*
 
1017
                 * Give the PreParseColumnRefHook, if any, first shot.  If it returns
 
1018
                 * non-null then we should use that expression.
 
1019
                 */
 
1020
                if (pstate->p_pre_columnref_hook != NULL)
 
1021
                {
 
1022
                        Node       *node;
 
1023
 
 
1024
                        node = (*pstate->p_pre_columnref_hook) (pstate, cref);
 
1025
                        if (node != NULL)
 
1026
                                return ExpandRowReference(pstate, node, make_target_entry);
 
1027
                }
 
1028
 
 
1029
                switch (numnames)
 
1030
                {
 
1031
                        case 2:
 
1032
                                relname = strVal(linitial(fields));
 
1033
                                rte = refnameRangeTblEntry(pstate, nspname, relname,
 
1034
                                                                                   cref->location,
 
1035
                                                                                   &levels_up);
 
1036
                                break;
 
1037
                        case 3:
 
1038
                                nspname = strVal(linitial(fields));
 
1039
                                relname = strVal(lsecond(fields));
 
1040
                                rte = refnameRangeTblEntry(pstate, nspname, relname,
 
1041
                                                                                   cref->location,
 
1042
                                                                                   &levels_up);
 
1043
                                break;
 
1044
                        case 4:
 
1045
                                {
 
1046
                                        char       *catname = strVal(linitial(fields));
 
1047
 
 
1048
                                        /*
 
1049
                                         * We check the catalog name and then ignore it.
 
1050
                                         */
 
1051
                                        if (strcmp(catname, get_database_name(MyDatabaseId)) != 0)
 
1052
                                        {
 
1053
                                                crserr = CRSERR_WRONG_DB;
 
1054
                                                break;
 
1055
                                        }
 
1056
                                        nspname = strVal(lsecond(fields));
 
1057
                                        relname = strVal(lthird(fields));
 
1058
                                        rte = refnameRangeTblEntry(pstate, nspname, relname,
 
1059
                                                                                           cref->location,
 
1060
                                                                                           &levels_up);
 
1061
                                        break;
 
1062
                                }
 
1063
                        default:
 
1064
                                crserr = CRSERR_TOO_MANY;
 
1065
                                break;
 
1066
                }
 
1067
 
 
1068
                /*
 
1069
                 * Now give the PostParseColumnRefHook, if any, a chance. We cheat a
 
1070
                 * bit by passing the RangeTblEntry, not a Var, as the planned
 
1071
                 * translation.  (A single Var wouldn't be strictly correct anyway.
 
1072
                 * This convention allows hooks that really care to know what is
 
1073
                 * happening.)
 
1074
                 */
 
1075
                if (pstate->p_post_columnref_hook != NULL)
 
1076
                {
 
1077
                        Node       *node;
 
1078
 
 
1079
                        node = (*pstate->p_post_columnref_hook) (pstate, cref,
 
1080
                                                                                                         (Node *) rte);
 
1081
                        if (node != NULL)
 
1082
                        {
 
1083
                                if (rte != NULL)
 
1084
                                        ereport(ERROR,
 
1085
                                                        (errcode(ERRCODE_AMBIGUOUS_COLUMN),
 
1086
                                                         errmsg("column reference \"%s\" is ambiguous",
 
1087
                                                                        NameListToString(cref->fields)),
 
1088
                                                         parser_errposition(pstate, cref->location)));
 
1089
                                return ExpandRowReference(pstate, node, make_target_entry);
 
1090
                        }
 
1091
                }
 
1092
 
 
1093
                /*
 
1094
                 * Throw error if no translation found.
 
1095
                 */
 
1096
                if (rte == NULL)
 
1097
                {
 
1098
                        switch (crserr)
 
1099
                        {
 
1100
                                case CRSERR_NO_RTE:
 
1101
                                        errorMissingRTE(pstate, makeRangeVar(nspname, relname,
 
1102
                                                                                                                 cref->location));
 
1103
                                        break;
 
1104
                                case CRSERR_WRONG_DB:
 
1105
                                        ereport(ERROR,
 
1106
                                                        (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 
1107
                                                         errmsg("cross-database references are not implemented: %s",
 
1108
                                                                        NameListToString(cref->fields)),
 
1109
                                                         parser_errposition(pstate, cref->location)));
 
1110
                                        break;
 
1111
                                case CRSERR_TOO_MANY:
 
1112
                                        ereport(ERROR,
 
1113
                                                        (errcode(ERRCODE_SYNTAX_ERROR),
 
1114
                                                         errmsg("improper qualified name (too many dotted names): %s",
 
1115
                                                                        NameListToString(cref->fields)),
 
1116
                                                         parser_errposition(pstate, cref->location)));
 
1117
                                        break;
 
1118
                        }
 
1119
                }
 
1120
 
 
1121
                /*
 
1122
                 * OK, expand the RTE into fields.
 
1123
                 */
 
1124
                return ExpandSingleTable(pstate, rte, cref->location, make_target_entry);
 
1125
        }
 
1126
}
 
1127
 
 
1128
/*
 
1129
 * ExpandAllTables()
 
1130
 *              Transforms '*' (in the target list) into a list of targetlist entries.
 
1131
 *
 
1132
 * tlist entries are generated for each relation visible for unqualified
 
1133
 * column name access.  We do not consider qualified-name-only entries because
 
1134
 * that would include input tables of aliasless JOINs, NEW/OLD pseudo-entries,
 
1135
 * etc.
 
1136
 *
 
1137
 * The referenced relations/columns are marked as requiring SELECT access.
 
1138
 */
 
1139
static List *
 
1140
ExpandAllTables(ParseState *pstate, int location)
 
1141
{
 
1142
        List       *target = NIL;
 
1143
        bool            found_table = false;
 
1144
        ListCell   *l;
 
1145
 
 
1146
        foreach(l, pstate->p_namespace)
 
1147
        {
 
1148
                ParseNamespaceItem *nsitem = (ParseNamespaceItem *) lfirst(l);
 
1149
                RangeTblEntry *rte = nsitem->p_rte;
 
1150
 
 
1151
                /* Ignore table-only items */
 
1152
                if (!nsitem->p_cols_visible)
 
1153
                        continue;
 
1154
                /* Should not have any lateral-only items when parsing targetlist */
 
1155
                Assert(!nsitem->p_lateral_only);
 
1156
                /* Remember we found a p_cols_visible item */
 
1157
                found_table = true;
 
1158
 
 
1159
                target = list_concat(target,
 
1160
                                                         expandRelAttrs(pstate,
 
1161
                                                                                        rte,
 
1162
                                                                                        RTERangeTablePosn(pstate, rte,
 
1163
                                                                                                                          NULL),
 
1164
                                                                                        0,
 
1165
                                                                                        location));
 
1166
        }
 
1167
 
 
1168
        /*
 
1169
         * Check for "SELECT *;".  We do it this way, rather than checking for
 
1170
         * target == NIL, because we want to allow SELECT * FROM a zero_column
 
1171
         * table.
 
1172
         */
 
1173
        if (!found_table)
 
1174
                ereport(ERROR,
 
1175
                                (errcode(ERRCODE_SYNTAX_ERROR),
 
1176
                                 errmsg("SELECT * with no tables specified is not valid"),
 
1177
                                 parser_errposition(pstate, location)));
 
1178
 
 
1179
        return target;
 
1180
}
 
1181
 
 
1182
/*
 
1183
 * ExpandIndirectionStar()
 
1184
 *              Transforms foo.* into a list of expressions or targetlist entries.
 
1185
 *
 
1186
 * This handles the case where '*' appears as the last item in A_Indirection.
 
1187
 * The code is shared between the case of foo.* at the top level in a SELECT
 
1188
 * target list (where we want TargetEntry nodes in the result) and foo.* in
 
1189
 * a ROW() or VALUES() construct (where we want just bare expressions).
 
1190
 * For robustness, we use a separate "make_target_entry" flag to control
 
1191
 * this rather than relying on exprKind.
 
1192
 */
 
1193
static List *
 
1194
ExpandIndirectionStar(ParseState *pstate, A_Indirection *ind,
 
1195
                                          bool make_target_entry, ParseExprKind exprKind)
 
1196
{
 
1197
        Node       *expr;
 
1198
 
 
1199
        /* Strip off the '*' to create a reference to the rowtype object */
 
1200
        ind = copyObject(ind);
 
1201
        ind->indirection = list_truncate(ind->indirection,
 
1202
                                                                         list_length(ind->indirection) - 1);
 
1203
 
 
1204
        /* And transform that */
 
1205
        expr = transformExpr(pstate, (Node *) ind, exprKind);
 
1206
 
 
1207
        /* Expand the rowtype expression into individual fields */
 
1208
        return ExpandRowReference(pstate, expr, make_target_entry);
 
1209
}
 
1210
 
 
1211
/*
 
1212
 * ExpandSingleTable()
 
1213
 *              Transforms foo.* into a list of expressions or targetlist entries.
 
1214
 *
 
1215
 * This handles the case where foo has been determined to be a simple
 
1216
 * reference to an RTE, so we can just generate Vars for the expressions.
 
1217
 *
 
1218
 * The referenced columns are marked as requiring SELECT access.
 
1219
 */
 
1220
static List *
 
1221
ExpandSingleTable(ParseState *pstate, RangeTblEntry *rte,
 
1222
                                  int location, bool make_target_entry)
 
1223
{
 
1224
        int                     sublevels_up;
 
1225
        int                     rtindex;
 
1226
 
 
1227
        rtindex = RTERangeTablePosn(pstate, rte, &sublevels_up);
 
1228
 
 
1229
        if (make_target_entry)
 
1230
        {
 
1231
                /* expandRelAttrs handles permissions marking */
 
1232
                return expandRelAttrs(pstate, rte, rtindex, sublevels_up,
 
1233
                                                          location);
 
1234
        }
 
1235
        else
 
1236
        {
 
1237
                List       *vars;
 
1238
                ListCell   *l;
 
1239
 
 
1240
                expandRTE(rte, rtindex, sublevels_up, location, false,
 
1241
                                  NULL, &vars);
 
1242
 
 
1243
                /*
 
1244
                 * Require read access to the table.  This is normally redundant with
 
1245
                 * the markVarForSelectPriv calls below, but not if the table has zero
 
1246
                 * columns.
 
1247
                 */
 
1248
                rte->requiredPerms |= ACL_SELECT;
 
1249
 
 
1250
                /* Require read access to each column */
 
1251
                foreach(l, vars)
 
1252
                {
 
1253
                        Var                *var = (Var *) lfirst(l);
 
1254
 
 
1255
                        markVarForSelectPriv(pstate, var, rte);
 
1256
                }
 
1257
 
 
1258
                return vars;
 
1259
        }
 
1260
}
 
1261
 
 
1262
/*
 
1263
 * ExpandRowReference()
 
1264
 *              Transforms foo.* into a list of expressions or targetlist entries.
 
1265
 *
 
1266
 * This handles the case where foo is an arbitrary expression of composite
 
1267
 * type.
 
1268
 */
 
1269
static List *
 
1270
ExpandRowReference(ParseState *pstate, Node *expr,
 
1271
                                   bool make_target_entry)
 
1272
{
 
1273
        List       *result = NIL;
 
1274
        TupleDesc       tupleDesc;
 
1275
        int                     numAttrs;
 
1276
        int                     i;
 
1277
 
 
1278
        /*
 
1279
         * If the rowtype expression is a whole-row Var, we can expand the fields
 
1280
         * as simple Vars.      Note: if the RTE is a relation, this case leaves us
 
1281
         * with the RTE's selectedCols bitmap showing the whole row as needing
 
1282
         * select permission, as well as the individual columns.  However, we can
 
1283
         * only get here for weird notations like (table.*).*, so it's not worth
 
1284
         * trying to clean up --- arguably, the permissions marking is correct
 
1285
         * anyway for such cases.
 
1286
         */
 
1287
        if (IsA(expr, Var) &&
 
1288
                ((Var *) expr)->varattno == InvalidAttrNumber)
 
1289
        {
 
1290
                Var                *var = (Var *) expr;
 
1291
                RangeTblEntry *rte;
 
1292
 
 
1293
                rte = GetRTEByRangeTablePosn(pstate, var->varno, var->varlevelsup);
 
1294
                return ExpandSingleTable(pstate, rte, var->location, make_target_entry);
 
1295
        }
 
1296
 
 
1297
        /*
 
1298
         * Otherwise we have to do it the hard way.  Our current implementation is
 
1299
         * to generate multiple copies of the expression and do FieldSelects.
 
1300
         * (This can be pretty inefficient if the expression involves nontrivial
 
1301
         * computation :-(.)
 
1302
         *
 
1303
         * Verify it's a composite type, and get the tupdesc.  We use
 
1304
         * get_expr_result_type() because that can handle references to functions
 
1305
         * returning anonymous record types.  If that fails, use
 
1306
         * lookup_rowtype_tupdesc(), which will almost certainly fail as well, but
 
1307
         * it will give an appropriate error message.
 
1308
         *
 
1309
         * If it's a Var of type RECORD, we have to work even harder: we have to
 
1310
         * find what the Var refers to, and pass that to get_expr_result_type.
 
1311
         * That task is handled by expandRecordVariable().
 
1312
         */
 
1313
        if (IsA(expr, Var) &&
 
1314
                ((Var *) expr)->vartype == RECORDOID)
 
1315
                tupleDesc = expandRecordVariable(pstate, (Var *) expr, 0);
 
1316
        else if (get_expr_result_type(expr, NULL, &tupleDesc) != TYPEFUNC_COMPOSITE)
 
1317
                tupleDesc = lookup_rowtype_tupdesc_copy(exprType(expr),
 
1318
                                                                                                exprTypmod(expr));
 
1319
        Assert(tupleDesc);
 
1320
 
 
1321
        /* Generate a list of references to the individual fields */
 
1322
        numAttrs = tupleDesc->natts;
 
1323
        for (i = 0; i < numAttrs; i++)
 
1324
        {
 
1325
                Form_pg_attribute att = tupleDesc->attrs[i];
 
1326
                FieldSelect *fselect;
 
1327
 
 
1328
                if (att->attisdropped)
 
1329
                        continue;
 
1330
 
 
1331
                fselect = makeNode(FieldSelect);
 
1332
                fselect->arg = (Expr *) copyObject(expr);
 
1333
                fselect->fieldnum = i + 1;
 
1334
                fselect->resulttype = att->atttypid;
 
1335
                fselect->resulttypmod = att->atttypmod;
 
1336
                /* save attribute's collation for parse_collate.c */
 
1337
                fselect->resultcollid = att->attcollation;
 
1338
 
 
1339
                if (make_target_entry)
 
1340
                {
 
1341
                        /* add TargetEntry decoration */
 
1342
                        TargetEntry *te;
 
1343
 
 
1344
                        te = makeTargetEntry((Expr *) fselect,
 
1345
                                                                 (AttrNumber) pstate->p_next_resno++,
 
1346
                                                                 pstrdup(NameStr(att->attname)),
 
1347
                                                                 false);
 
1348
                        result = lappend(result, te);
 
1349
                }
 
1350
                else
 
1351
                        result = lappend(result, fselect);
 
1352
        }
 
1353
 
 
1354
        return result;
 
1355
}
 
1356
 
 
1357
/*
 
1358
 * expandRecordVariable
 
1359
 *              Get the tuple descriptor for a Var of type RECORD, if possible.
 
1360
 *
 
1361
 * Since no actual table or view column is allowed to have type RECORD, such
 
1362
 * a Var must refer to a JOIN or FUNCTION RTE or to a subquery output.  We
 
1363
 * drill down to find the ultimate defining expression and attempt to infer
 
1364
 * the tupdesc from it.  We ereport if we can't determine the tupdesc.
 
1365
 *
 
1366
 * levelsup is an extra offset to interpret the Var's varlevelsup correctly.
 
1367
 */
 
1368
TupleDesc
 
1369
expandRecordVariable(ParseState *pstate, Var *var, int levelsup)
 
1370
{
 
1371
        TupleDesc       tupleDesc;
 
1372
        int                     netlevelsup;
 
1373
        RangeTblEntry *rte;
 
1374
        AttrNumber      attnum;
 
1375
        Node       *expr;
 
1376
 
 
1377
        /* Check my caller didn't mess up */
 
1378
        Assert(IsA(var, Var));
 
1379
        Assert(var->vartype == RECORDOID);
 
1380
 
 
1381
        netlevelsup = var->varlevelsup + levelsup;
 
1382
        rte = GetRTEByRangeTablePosn(pstate, var->varno, netlevelsup);
 
1383
        attnum = var->varattno;
 
1384
 
 
1385
        if (attnum == InvalidAttrNumber)
 
1386
        {
 
1387
                /* Whole-row reference to an RTE, so expand the known fields */
 
1388
                List       *names,
 
1389
                                   *vars;
 
1390
                ListCell   *lname,
 
1391
                                   *lvar;
 
1392
                int                     i;
 
1393
 
 
1394
                expandRTE(rte, var->varno, 0, var->location, false,
 
1395
                                  &names, &vars);
 
1396
 
 
1397
                tupleDesc = CreateTemplateTupleDesc(list_length(vars), false);
 
1398
                i = 1;
 
1399
                forboth(lname, names, lvar, vars)
 
1400
                {
 
1401
                        char       *label = strVal(lfirst(lname));
 
1402
                        Node       *varnode = (Node *) lfirst(lvar);
 
1403
 
 
1404
                        TupleDescInitEntry(tupleDesc, i,
 
1405
                                                           label,
 
1406
                                                           exprType(varnode),
 
1407
                                                           exprTypmod(varnode),
 
1408
                                                           0);
 
1409
                        TupleDescInitEntryCollation(tupleDesc, i,
 
1410
                                                                                exprCollation(varnode));
 
1411
                        i++;
 
1412
                }
 
1413
                Assert(lname == NULL && lvar == NULL);  /* lists same length? */
 
1414
 
 
1415
                return tupleDesc;
 
1416
        }
 
1417
 
 
1418
        expr = (Node *) var;            /* default if we can't drill down */
 
1419
 
 
1420
        switch (rte->rtekind)
 
1421
        {
 
1422
                case RTE_RELATION:
 
1423
                case RTE_VALUES:
 
1424
 
 
1425
                        /*
 
1426
                         * This case should not occur: a column of a table or values list
 
1427
                         * shouldn't have type RECORD.  Fall through and fail (most
 
1428
                         * likely) at the bottom.
 
1429
                         */
 
1430
                        break;
 
1431
                case RTE_SUBQUERY:
 
1432
                        {
 
1433
                                /* Subselect-in-FROM: examine sub-select's output expr */
 
1434
                                TargetEntry *ste = get_tle_by_resno(rte->subquery->targetList,
 
1435
                                                                                                        attnum);
 
1436
 
 
1437
                                if (ste == NULL || ste->resjunk)
 
1438
                                        elog(ERROR, "subquery %s does not have attribute %d",
 
1439
                                                 rte->eref->aliasname, attnum);
 
1440
                                expr = (Node *) ste->expr;
 
1441
                                if (IsA(expr, Var))
 
1442
                                {
 
1443
                                        /*
 
1444
                                         * Recurse into the sub-select to see what its Var refers
 
1445
                                         * to.  We have to build an additional level of ParseState
 
1446
                                         * to keep in step with varlevelsup in the subselect.
 
1447
                                         */
 
1448
                                        ParseState      mypstate;
 
1449
 
 
1450
                                        MemSet(&mypstate, 0, sizeof(mypstate));
 
1451
                                        mypstate.parentParseState = pstate;
 
1452
                                        mypstate.p_rtable = rte->subquery->rtable;
 
1453
                                        /* don't bother filling the rest of the fake pstate */
 
1454
 
 
1455
                                        return expandRecordVariable(&mypstate, (Var *) expr, 0);
 
1456
                                }
 
1457
                                /* else fall through to inspect the expression */
 
1458
                        }
 
1459
                        break;
 
1460
                case RTE_JOIN:
 
1461
                        /* Join RTE --- recursively inspect the alias variable */
 
1462
                        Assert(attnum > 0 && attnum <= list_length(rte->joinaliasvars));
 
1463
                        expr = (Node *) list_nth(rte->joinaliasvars, attnum - 1);
 
1464
                        if (IsA(expr, Var))
 
1465
                                return expandRecordVariable(pstate, (Var *) expr, netlevelsup);
 
1466
                        /* else fall through to inspect the expression */
 
1467
                        break;
 
1468
                case RTE_FUNCTION:
 
1469
 
 
1470
                        /*
 
1471
                         * We couldn't get here unless a function is declared with one of
 
1472
                         * its result columns as RECORD, which is not allowed.
 
1473
                         */
 
1474
                        break;
 
1475
                case RTE_CTE:
 
1476
                        /* CTE reference: examine subquery's output expr */
 
1477
                        if (!rte->self_reference)
 
1478
                        {
 
1479
                                CommonTableExpr *cte = GetCTEForRTE(pstate, rte, netlevelsup);
 
1480
                                TargetEntry *ste;
 
1481
 
 
1482
                                ste = get_tle_by_resno(GetCTETargetList(cte), attnum);
 
1483
                                if (ste == NULL || ste->resjunk)
 
1484
                                        elog(ERROR, "subquery %s does not have attribute %d",
 
1485
                                                 rte->eref->aliasname, attnum);
 
1486
                                expr = (Node *) ste->expr;
 
1487
                                if (IsA(expr, Var))
 
1488
                                {
 
1489
                                        /*
 
1490
                                         * Recurse into the CTE to see what its Var refers to. We
 
1491
                                         * have to build an additional level of ParseState to keep
 
1492
                                         * in step with varlevelsup in the CTE; furthermore it
 
1493
                                         * could be an outer CTE.
 
1494
                                         */
 
1495
                                        ParseState      mypstate;
 
1496
                                        Index           levelsup;
 
1497
 
 
1498
                                        MemSet(&mypstate, 0, sizeof(mypstate));
 
1499
                                        /* this loop must work, since GetCTEForRTE did */
 
1500
                                        for (levelsup = 0;
 
1501
                                                 levelsup < rte->ctelevelsup + netlevelsup;
 
1502
                                                 levelsup++)
 
1503
                                                pstate = pstate->parentParseState;
 
1504
                                        mypstate.parentParseState = pstate;
 
1505
                                        mypstate.p_rtable = ((Query *) cte->ctequery)->rtable;
 
1506
                                        /* don't bother filling the rest of the fake pstate */
 
1507
 
 
1508
                                        return expandRecordVariable(&mypstate, (Var *) expr, 0);
 
1509
                                }
 
1510
                                /* else fall through to inspect the expression */
 
1511
                        }
 
1512
                        break;
 
1513
        }
 
1514
 
 
1515
        /*
 
1516
         * We now have an expression we can't expand any more, so see if
 
1517
         * get_expr_result_type() can do anything with it.      If not, pass to
 
1518
         * lookup_rowtype_tupdesc() which will probably fail, but will give an
 
1519
         * appropriate error message while failing.
 
1520
         */
 
1521
        if (get_expr_result_type(expr, NULL, &tupleDesc) != TYPEFUNC_COMPOSITE)
 
1522
                tupleDesc = lookup_rowtype_tupdesc_copy(exprType(expr),
 
1523
                                                                                                exprTypmod(expr));
 
1524
 
 
1525
        return tupleDesc;
 
1526
}
 
1527
 
 
1528
 
 
1529
/*
 
1530
 * FigureColname -
 
1531
 *        if the name of the resulting column is not specified in the target
 
1532
 *        list, we have to guess a suitable name.  The SQL spec provides some
 
1533
 *        guidance, but not much...
 
1534
 *
 
1535
 * Note that the argument is the *untransformed* parse tree for the target
 
1536
 * item.  This is a shade easier to work with than the transformed tree.
 
1537
 */
 
1538
char *
 
1539
FigureColname(Node *node)
 
1540
{
 
1541
        char       *name = NULL;
 
1542
 
 
1543
        (void) FigureColnameInternal(node, &name);
 
1544
        if (name != NULL)
 
1545
                return name;
 
1546
        /* default result if we can't guess anything */
 
1547
        return "?column?";
 
1548
}
 
1549
 
 
1550
/*
 
1551
 * FigureIndexColname -
 
1552
 *        choose the name for an expression column in an index
 
1553
 *
 
1554
 * This is actually just like FigureColname, except we return NULL if
 
1555
 * we can't pick a good name.
 
1556
 */
 
1557
char *
 
1558
FigureIndexColname(Node *node)
 
1559
{
 
1560
        char       *name = NULL;
 
1561
 
 
1562
        (void) FigureColnameInternal(node, &name);
 
1563
        return name;
 
1564
}
 
1565
 
 
1566
/*
 
1567
 * FigureColnameInternal -
 
1568
 *        internal workhorse for FigureColname
 
1569
 *
 
1570
 * Return value indicates strength of confidence in result:
 
1571
 *              0 - no information
 
1572
 *              1 - second-best name choice
 
1573
 *              2 - good name choice
 
1574
 * The return value is actually only used internally.
 
1575
 * If the result isn't zero, *name is set to the chosen name.
 
1576
 */
 
1577
static int
 
1578
FigureColnameInternal(Node *node, char **name)
 
1579
{
 
1580
        int                     strength = 0;
 
1581
 
 
1582
        if (node == NULL)
 
1583
                return strength;
 
1584
 
 
1585
        switch (nodeTag(node))
 
1586
        {
 
1587
                case T_ColumnRef:
 
1588
                        {
 
1589
                                char       *fname = NULL;
 
1590
                                ListCell   *l;
 
1591
 
 
1592
                                /* find last field name, if any, ignoring "*" */
 
1593
                                foreach(l, ((ColumnRef *) node)->fields)
 
1594
                                {
 
1595
                                        Node       *i = lfirst(l);
 
1596
 
 
1597
                                        if (IsA(i, String))
 
1598
                                                fname = strVal(i);
 
1599
                                }
 
1600
                                if (fname)
 
1601
                                {
 
1602
                                        *name = fname;
 
1603
                                        return 2;
 
1604
                                }
 
1605
                        }
 
1606
                        break;
 
1607
                case T_A_Indirection:
 
1608
                        {
 
1609
                                A_Indirection *ind = (A_Indirection *) node;
 
1610
                                char       *fname = NULL;
 
1611
                                ListCell   *l;
 
1612
 
 
1613
                                /* find last field name, if any, ignoring "*" and subscripts */
 
1614
                                foreach(l, ind->indirection)
 
1615
                                {
 
1616
                                        Node       *i = lfirst(l);
 
1617
 
 
1618
                                        if (IsA(i, String))
 
1619
                                                fname = strVal(i);
 
1620
                                }
 
1621
                                if (fname)
 
1622
                                {
 
1623
                                        *name = fname;
 
1624
                                        return 2;
 
1625
                                }
 
1626
                                return FigureColnameInternal(ind->arg, name);
 
1627
                        }
 
1628
                        break;
 
1629
                case T_FuncCall:
 
1630
                        *name = strVal(llast(((FuncCall *) node)->funcname));
 
1631
                        return 2;
 
1632
                case T_A_Expr:
 
1633
                        /* make nullif() act like a regular function */
 
1634
                        if (((A_Expr *) node)->kind == AEXPR_NULLIF)
 
1635
                        {
 
1636
                                *name = "nullif";
 
1637
                                return 2;
 
1638
                        }
 
1639
                        break;
 
1640
                case T_TypeCast:
 
1641
                        strength = FigureColnameInternal(((TypeCast *) node)->arg,
 
1642
                                                                                         name);
 
1643
                        if (strength <= 1)
 
1644
                        {
 
1645
                                if (((TypeCast *) node)->typeName != NULL)
 
1646
                                {
 
1647
                                        *name = strVal(llast(((TypeCast *) node)->typeName->names));
 
1648
                                        return 1;
 
1649
                                }
 
1650
                        }
 
1651
                        break;
 
1652
                case T_CollateClause:
 
1653
                        return FigureColnameInternal(((CollateClause *) node)->arg, name);
 
1654
                case T_SubLink:
 
1655
                        switch (((SubLink *) node)->subLinkType)
 
1656
                        {
 
1657
                                case EXISTS_SUBLINK:
 
1658
                                        *name = "exists";
 
1659
                                        return 2;
 
1660
                                case ARRAY_SUBLINK:
 
1661
                                        *name = "array";
 
1662
                                        return 2;
 
1663
                                case EXPR_SUBLINK:
 
1664
                                        {
 
1665
                                                /* Get column name of the subquery's single target */
 
1666
                                                SubLink    *sublink = (SubLink *) node;
 
1667
                                                Query      *query = (Query *) sublink->subselect;
 
1668
 
 
1669
                                                /*
 
1670
                                                 * The subquery has probably already been transformed,
 
1671
                                                 * but let's be careful and check that.  (The reason
 
1672
                                                 * we can see a transformed subquery here is that
 
1673
                                                 * transformSubLink is lazy and modifies the SubLink
 
1674
                                                 * node in-place.)
 
1675
                                                 */
 
1676
                                                if (IsA(query, Query))
 
1677
                                                {
 
1678
                                                        TargetEntry *te = (TargetEntry *) linitial(query->targetList);
 
1679
 
 
1680
                                                        if (te->resname)
 
1681
                                                        {
 
1682
                                                                *name = te->resname;
 
1683
                                                                return 2;
 
1684
                                                        }
 
1685
                                                }
 
1686
                                        }
 
1687
                                        break;
 
1688
                                        /* As with other operator-like nodes, these have no names */
 
1689
                                case ALL_SUBLINK:
 
1690
                                case ANY_SUBLINK:
 
1691
                                case ROWCOMPARE_SUBLINK:
 
1692
                                case CTE_SUBLINK:
 
1693
                                        break;
 
1694
                        }
 
1695
                        break;
 
1696
                case T_CaseExpr:
 
1697
                        strength = FigureColnameInternal((Node *) ((CaseExpr *) node)->defresult,
 
1698
                                                                                         name);
 
1699
                        if (strength <= 1)
 
1700
                        {
 
1701
                                *name = "case";
 
1702
                                return 1;
 
1703
                        }
 
1704
                        break;
 
1705
                case T_A_ArrayExpr:
 
1706
                        /* make ARRAY[] act like a function */
 
1707
                        *name = "array";
 
1708
                        return 2;
 
1709
                case T_RowExpr:
 
1710
                        /* make ROW() act like a function */
 
1711
                        *name = "row";
 
1712
                        return 2;
 
1713
                case T_CoalesceExpr:
 
1714
                        /* make coalesce() act like a regular function */
 
1715
                        *name = "coalesce";
 
1716
                        return 2;
 
1717
                case T_MinMaxExpr:
 
1718
                        /* make greatest/least act like a regular function */
 
1719
                        switch (((MinMaxExpr *) node)->op)
 
1720
                        {
 
1721
                                case IS_GREATEST:
 
1722
                                        *name = "greatest";
 
1723
                                        return 2;
 
1724
                                case IS_LEAST:
 
1725
                                        *name = "least";
 
1726
                                        return 2;
 
1727
                        }
 
1728
                        break;
 
1729
                case T_XmlExpr:
 
1730
                        /* make SQL/XML functions act like a regular function */
 
1731
                        switch (((XmlExpr *) node)->op)
 
1732
                        {
 
1733
                                case IS_XMLCONCAT:
 
1734
                                        *name = "xmlconcat";
 
1735
                                        return 2;
 
1736
                                case IS_XMLELEMENT:
 
1737
                                        *name = "xmlelement";
 
1738
                                        return 2;
 
1739
                                case IS_XMLFOREST:
 
1740
                                        *name = "xmlforest";
 
1741
                                        return 2;
 
1742
                                case IS_XMLPARSE:
 
1743
                                        *name = "xmlparse";
 
1744
                                        return 2;
 
1745
                                case IS_XMLPI:
 
1746
                                        *name = "xmlpi";
 
1747
                                        return 2;
 
1748
                                case IS_XMLROOT:
 
1749
                                        *name = "xmlroot";
 
1750
                                        return 2;
 
1751
                                case IS_XMLSERIALIZE:
 
1752
                                        *name = "xmlserialize";
 
1753
                                        return 2;
 
1754
                                case IS_DOCUMENT:
 
1755
                                        /* nothing */
 
1756
                                        break;
 
1757
                        }
 
1758
                        break;
 
1759
                case T_XmlSerialize:
 
1760
                        *name = "xmlserialize";
 
1761
                        return 2;
 
1762
                default:
 
1763
                        break;
 
1764
        }
 
1765
 
 
1766
        return strength;
 
1767
}