00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "postgres.h"
00016
00017 #include "catalog/pg_collation.h"
00018 #include "catalog/pg_type.h"
00019 #include "nodes/nodeFuncs.h"
00020 #include "parser/analyze.h"
00021 #include "parser/parse_cte.h"
00022 #include "utils/builtins.h"
00023 #include "utils/lsyscache.h"
00024
00025
00026
00027 typedef enum
00028 {
00029 RECURSION_OK,
00030 RECURSION_NONRECURSIVETERM,
00031 RECURSION_SUBLINK,
00032 RECURSION_OUTERJOIN,
00033 RECURSION_INTERSECT,
00034 RECURSION_EXCEPT
00035 } RecursionContext;
00036
00037
00038 static const char *const recursion_errormsgs[] = {
00039
00040 NULL,
00041
00042 gettext_noop("recursive reference to query \"%s\" must not appear within its non-recursive term"),
00043
00044 gettext_noop("recursive reference to query \"%s\" must not appear within a subquery"),
00045
00046 gettext_noop("recursive reference to query \"%s\" must not appear within an outer join"),
00047
00048 gettext_noop("recursive reference to query \"%s\" must not appear within INTERSECT"),
00049
00050 gettext_noop("recursive reference to query \"%s\" must not appear within EXCEPT")
00051 };
00052
00053
00054
00055
00056
00057
00058
00059 typedef struct CteItem
00060 {
00061 CommonTableExpr *cte;
00062 int id;
00063 Bitmapset *depends_on;
00064 } CteItem;
00065
00066
00067 typedef struct CteState
00068 {
00069
00070 ParseState *pstate;
00071 CteItem *items;
00072 int numitems;
00073
00074 int curitem;
00075 List *innerwiths;
00076
00077 int selfrefcount;
00078 RecursionContext context;
00079 } CteState;
00080
00081
00082 static void analyzeCTE(ParseState *pstate, CommonTableExpr *cte);
00083
00084
00085 static void makeDependencyGraph(CteState *cstate);
00086 static bool makeDependencyGraphWalker(Node *node, CteState *cstate);
00087 static void TopologicalSort(ParseState *pstate, CteItem *items, int numitems);
00088
00089
00090 static void checkWellFormedRecursion(CteState *cstate);
00091 static bool checkWellFormedRecursionWalker(Node *node, CteState *cstate);
00092 static void checkWellFormedSelectStmt(SelectStmt *stmt, CteState *cstate);
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104 List *
00105 transformWithClause(ParseState *pstate, WithClause *withClause)
00106 {
00107 ListCell *lc;
00108
00109
00110 Assert(pstate->p_ctenamespace == NIL);
00111 Assert(pstate->p_future_ctes == NIL);
00112
00113
00114
00115
00116
00117
00118
00119
00120 foreach(lc, withClause->ctes)
00121 {
00122 CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc);
00123 ListCell *rest;
00124
00125 for_each_cell(rest, lnext(lc))
00126 {
00127 CommonTableExpr *cte2 = (CommonTableExpr *) lfirst(rest);
00128
00129 if (strcmp(cte->ctename, cte2->ctename) == 0)
00130 ereport(ERROR,
00131 (errcode(ERRCODE_DUPLICATE_ALIAS),
00132 errmsg("WITH query name \"%s\" specified more than once",
00133 cte2->ctename),
00134 parser_errposition(pstate, cte2->location)));
00135 }
00136
00137 cte->cterecursive = false;
00138 cte->cterefcount = 0;
00139
00140 if (!IsA(cte->ctequery, SelectStmt))
00141 {
00142
00143 Assert(IsA(cte->ctequery, InsertStmt) ||
00144 IsA(cte->ctequery, UpdateStmt) ||
00145 IsA(cte->ctequery, DeleteStmt));
00146
00147 pstate->p_hasModifyingCTE = true;
00148 }
00149 }
00150
00151 if (withClause->recursive)
00152 {
00153
00154
00155
00156
00157
00158 CteState cstate;
00159 int i;
00160
00161 cstate.pstate = pstate;
00162 cstate.numitems = list_length(withClause->ctes);
00163 cstate.items = (CteItem *) palloc0(cstate.numitems * sizeof(CteItem));
00164 i = 0;
00165 foreach(lc, withClause->ctes)
00166 {
00167 cstate.items[i].cte = (CommonTableExpr *) lfirst(lc);
00168 cstate.items[i].id = i;
00169 i++;
00170 }
00171
00172
00173
00174
00175
00176 makeDependencyGraph(&cstate);
00177
00178
00179
00180
00181 checkWellFormedRecursion(&cstate);
00182
00183
00184
00185
00186
00187
00188
00189 for (i = 0; i < cstate.numitems; i++)
00190 {
00191 CommonTableExpr *cte = cstate.items[i].cte;
00192
00193 pstate->p_ctenamespace = lappend(pstate->p_ctenamespace, cte);
00194 }
00195
00196
00197
00198
00199 for (i = 0; i < cstate.numitems; i++)
00200 {
00201 CommonTableExpr *cte = cstate.items[i].cte;
00202
00203 analyzeCTE(pstate, cte);
00204 }
00205 }
00206 else
00207 {
00208
00209
00210
00211
00212
00213
00214
00215 pstate->p_future_ctes = list_copy(withClause->ctes);
00216
00217 foreach(lc, withClause->ctes)
00218 {
00219 CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc);
00220
00221 analyzeCTE(pstate, cte);
00222 pstate->p_ctenamespace = lappend(pstate->p_ctenamespace, cte);
00223 pstate->p_future_ctes = list_delete_first(pstate->p_future_ctes);
00224 }
00225 }
00226
00227 return pstate->p_ctenamespace;
00228 }
00229
00230
00231
00232
00233
00234
00235
00236 static void
00237 analyzeCTE(ParseState *pstate, CommonTableExpr *cte)
00238 {
00239 Query *query;
00240
00241
00242 Assert(!IsA(cte->ctequery, Query));
00243
00244 query = parse_sub_analyze(cte->ctequery, pstate, cte, false);
00245 cte->ctequery = (Node *) query;
00246
00247
00248
00249
00250
00251 if (!IsA(query, Query))
00252 elog(ERROR, "unexpected non-Query statement in WITH");
00253 if (query->utilityStmt != NULL)
00254 elog(ERROR, "unexpected utility statement in WITH");
00255
00256
00257
00258
00259
00260 if (query->commandType != CMD_SELECT &&
00261 pstate->parentParseState != NULL)
00262 ereport(ERROR,
00263 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
00264 errmsg("WITH clause containing a data-modifying statement must be at the top level"),
00265 parser_errposition(pstate, cte->location)));
00266
00267
00268
00269
00270
00271
00272 query->canSetTag = false;
00273
00274 if (!cte->cterecursive)
00275 {
00276
00277 analyzeCTETargetList(pstate, cte, GetCTETargetList(cte));
00278 }
00279 else
00280 {
00281
00282
00283
00284
00285
00286
00287 ListCell *lctlist,
00288 *lctyp,
00289 *lctypmod,
00290 *lccoll;
00291 int varattno;
00292
00293 lctyp = list_head(cte->ctecoltypes);
00294 lctypmod = list_head(cte->ctecoltypmods);
00295 lccoll = list_head(cte->ctecolcollations);
00296 varattno = 0;
00297 foreach(lctlist, GetCTETargetList(cte))
00298 {
00299 TargetEntry *te = (TargetEntry *) lfirst(lctlist);
00300 Node *texpr;
00301
00302 if (te->resjunk)
00303 continue;
00304 varattno++;
00305 Assert(varattno == te->resno);
00306 if (lctyp == NULL || lctypmod == NULL || lccoll == NULL)
00307 elog(ERROR, "wrong number of output columns in WITH");
00308 texpr = (Node *) te->expr;
00309 if (exprType(texpr) != lfirst_oid(lctyp) ||
00310 exprTypmod(texpr) != lfirst_int(lctypmod))
00311 ereport(ERROR,
00312 (errcode(ERRCODE_DATATYPE_MISMATCH),
00313 errmsg("recursive query \"%s\" column %d has type %s in non-recursive term but type %s overall",
00314 cte->ctename, varattno,
00315 format_type_with_typemod(lfirst_oid(lctyp),
00316 lfirst_int(lctypmod)),
00317 format_type_with_typemod(exprType(texpr),
00318 exprTypmod(texpr))),
00319 errhint("Cast the output of the non-recursive term to the correct type."),
00320 parser_errposition(pstate, exprLocation(texpr))));
00321 if (exprCollation(texpr) != lfirst_oid(lccoll))
00322 ereport(ERROR,
00323 (errcode(ERRCODE_COLLATION_MISMATCH),
00324 errmsg("recursive query \"%s\" column %d has collation \"%s\" in non-recursive term but collation \"%s\" overall",
00325 cte->ctename, varattno,
00326 get_collation_name(lfirst_oid(lccoll)),
00327 get_collation_name(exprCollation(texpr))),
00328 errhint("Use the COLLATE clause to set the collation of the non-recursive term."),
00329 parser_errposition(pstate, exprLocation(texpr))));
00330 lctyp = lnext(lctyp);
00331 lctypmod = lnext(lctypmod);
00332 lccoll = lnext(lccoll);
00333 }
00334 if (lctyp != NULL || lctypmod != NULL || lccoll != NULL)
00335 elog(ERROR, "wrong number of output columns in WITH");
00336 }
00337 }
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351 void
00352 analyzeCTETargetList(ParseState *pstate, CommonTableExpr *cte, List *tlist)
00353 {
00354 int numaliases;
00355 int varattno;
00356 ListCell *tlistitem;
00357
00358
00359 Assert(cte->ctecolnames == NIL);
00360
00361
00362
00363
00364
00365
00366
00367
00368 cte->ctecolnames = copyObject(cte->aliascolnames);
00369 cte->ctecoltypes = cte->ctecoltypmods = cte->ctecolcollations = NIL;
00370 numaliases = list_length(cte->aliascolnames);
00371 varattno = 0;
00372 foreach(tlistitem, tlist)
00373 {
00374 TargetEntry *te = (TargetEntry *) lfirst(tlistitem);
00375 Oid coltype;
00376 int32 coltypmod;
00377 Oid colcoll;
00378
00379 if (te->resjunk)
00380 continue;
00381 varattno++;
00382 Assert(varattno == te->resno);
00383 if (varattno > numaliases)
00384 {
00385 char *attrname;
00386
00387 attrname = pstrdup(te->resname);
00388 cte->ctecolnames = lappend(cte->ctecolnames, makeString(attrname));
00389 }
00390 coltype = exprType((Node *) te->expr);
00391 coltypmod = exprTypmod((Node *) te->expr);
00392 colcoll = exprCollation((Node *) te->expr);
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405 if (cte->cterecursive && coltype == UNKNOWNOID)
00406 {
00407 coltype = TEXTOID;
00408 coltypmod = -1;
00409 if (!OidIsValid(colcoll))
00410 colcoll = DEFAULT_COLLATION_OID;
00411 }
00412 cte->ctecoltypes = lappend_oid(cte->ctecoltypes, coltype);
00413 cte->ctecoltypmods = lappend_int(cte->ctecoltypmods, coltypmod);
00414 cte->ctecolcollations = lappend_oid(cte->ctecolcollations, colcoll);
00415 }
00416 if (varattno < numaliases)
00417 ereport(ERROR,
00418 (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
00419 errmsg("WITH query \"%s\" has %d columns available but %d columns specified",
00420 cte->ctename, varattno, numaliases),
00421 parser_errposition(pstate, cte->location)));
00422 }
00423
00424
00425
00426
00427
00428
00429 static void
00430 makeDependencyGraph(CteState *cstate)
00431 {
00432 int i;
00433
00434 for (i = 0; i < cstate->numitems; i++)
00435 {
00436 CommonTableExpr *cte = cstate->items[i].cte;
00437
00438 cstate->curitem = i;
00439 cstate->innerwiths = NIL;
00440 makeDependencyGraphWalker((Node *) cte->ctequery, cstate);
00441 Assert(cstate->innerwiths == NIL);
00442 }
00443
00444 TopologicalSort(cstate->pstate, cstate->items, cstate->numitems);
00445 }
00446
00447
00448
00449
00450
00451 static bool
00452 makeDependencyGraphWalker(Node *node, CteState *cstate)
00453 {
00454 if (node == NULL)
00455 return false;
00456 if (IsA(node, RangeVar))
00457 {
00458 RangeVar *rv = (RangeVar *) node;
00459
00460
00461 if (!rv->schemaname)
00462 {
00463 ListCell *lc;
00464 int i;
00465
00466
00467 foreach(lc, cstate->innerwiths)
00468 {
00469 List *withlist = (List *) lfirst(lc);
00470 ListCell *lc2;
00471
00472 foreach(lc2, withlist)
00473 {
00474 CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc2);
00475
00476 if (strcmp(rv->relname, cte->ctename) == 0)
00477 return false;
00478 }
00479 }
00480
00481
00482 for (i = 0; i < cstate->numitems; i++)
00483 {
00484 CommonTableExpr *cte = cstate->items[i].cte;
00485
00486 if (strcmp(rv->relname, cte->ctename) == 0)
00487 {
00488 int myindex = cstate->curitem;
00489
00490 if (i != myindex)
00491 {
00492
00493 cstate->items[myindex].depends_on =
00494 bms_add_member(cstate->items[myindex].depends_on,
00495 cstate->items[i].id);
00496 }
00497 else
00498 {
00499
00500 cte->cterecursive = true;
00501 }
00502 break;
00503 }
00504 }
00505 }
00506 return false;
00507 }
00508 if (IsA(node, SelectStmt))
00509 {
00510 SelectStmt *stmt = (SelectStmt *) node;
00511 ListCell *lc;
00512
00513 if (stmt->withClause)
00514 {
00515 if (stmt->withClause->recursive)
00516 {
00517
00518
00519
00520
00521
00522 cstate->innerwiths = lcons(stmt->withClause->ctes,
00523 cstate->innerwiths);
00524 foreach(lc, stmt->withClause->ctes)
00525 {
00526 CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc);
00527
00528 (void) makeDependencyGraphWalker(cte->ctequery, cstate);
00529 }
00530 (void) raw_expression_tree_walker(node,
00531 makeDependencyGraphWalker,
00532 (void *) cstate);
00533 cstate->innerwiths = list_delete_first(cstate->innerwiths);
00534 }
00535 else
00536 {
00537
00538
00539
00540
00541 ListCell *cell1;
00542
00543 cstate->innerwiths = lcons(NIL, cstate->innerwiths);
00544 cell1 = list_head(cstate->innerwiths);
00545 foreach(lc, stmt->withClause->ctes)
00546 {
00547 CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc);
00548
00549 (void) makeDependencyGraphWalker(cte->ctequery, cstate);
00550 lfirst(cell1) = lappend((List *) lfirst(cell1), cte);
00551 }
00552 (void) raw_expression_tree_walker(node,
00553 makeDependencyGraphWalker,
00554 (void *) cstate);
00555 cstate->innerwiths = list_delete_first(cstate->innerwiths);
00556 }
00557
00558 return false;
00559 }
00560
00561 }
00562 if (IsA(node, WithClause))
00563 {
00564
00565
00566
00567
00568
00569 return false;
00570 }
00571 return raw_expression_tree_walker(node,
00572 makeDependencyGraphWalker,
00573 (void *) cstate);
00574 }
00575
00576
00577
00578
00579 static void
00580 TopologicalSort(ParseState *pstate, CteItem *items, int numitems)
00581 {
00582 int i,
00583 j;
00584
00585
00586 for (i = 0; i < numitems; i++)
00587 {
00588
00589 for (j = i; j < numitems; j++)
00590 {
00591 if (bms_is_empty(items[j].depends_on))
00592 break;
00593 }
00594
00595
00596 if (j >= numitems)
00597 ereport(ERROR,
00598 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
00599 errmsg("mutual recursion between WITH items is not implemented"),
00600 parser_errposition(pstate, items[i].cte->location)));
00601
00602
00603
00604
00605
00606 if (i != j)
00607 {
00608 CteItem tmp;
00609
00610 tmp = items[i];
00611 items[i] = items[j];
00612 items[j] = tmp;
00613 }
00614
00615
00616
00617
00618
00619 for (j = i + 1; j < numitems; j++)
00620 {
00621 items[j].depends_on = bms_del_member(items[j].depends_on,
00622 items[i].id);
00623 }
00624 }
00625 }
00626
00627
00628
00629
00630
00631 static void
00632 checkWellFormedRecursion(CteState *cstate)
00633 {
00634 int i;
00635
00636 for (i = 0; i < cstate->numitems; i++)
00637 {
00638 CommonTableExpr *cte = cstate->items[i].cte;
00639 SelectStmt *stmt = (SelectStmt *) cte->ctequery;
00640
00641 Assert(!IsA(stmt, Query));
00642
00643
00644 if (!cte->cterecursive)
00645 continue;
00646
00647
00648 if (!IsA(stmt, SelectStmt))
00649 ereport(ERROR,
00650 (errcode(ERRCODE_INVALID_RECURSION),
00651 errmsg("recursive query \"%s\" must not contain data-modifying statements",
00652 cte->ctename),
00653 parser_errposition(cstate->pstate, cte->location)));
00654
00655
00656 if (stmt->op != SETOP_UNION)
00657 ereport(ERROR,
00658 (errcode(ERRCODE_INVALID_RECURSION),
00659 errmsg("recursive query \"%s\" does not have the form non-recursive-term UNION [ALL] recursive-term",
00660 cte->ctename),
00661 parser_errposition(cstate->pstate, cte->location)));
00662
00663
00664 cstate->curitem = i;
00665 cstate->innerwiths = NIL;
00666 cstate->selfrefcount = 0;
00667 cstate->context = RECURSION_NONRECURSIVETERM;
00668 checkWellFormedRecursionWalker((Node *) stmt->larg, cstate);
00669 Assert(cstate->innerwiths == NIL);
00670
00671
00672 cstate->curitem = i;
00673 cstate->innerwiths = NIL;
00674 cstate->selfrefcount = 0;
00675 cstate->context = RECURSION_OK;
00676 checkWellFormedRecursionWalker((Node *) stmt->rarg, cstate);
00677 Assert(cstate->innerwiths == NIL);
00678 if (cstate->selfrefcount != 1)
00679 elog(ERROR, "missing recursive reference");
00680
00681
00682 if (stmt->withClause)
00683 {
00684 cstate->curitem = i;
00685 cstate->innerwiths = NIL;
00686 cstate->selfrefcount = 0;
00687 cstate->context = RECURSION_SUBLINK;
00688 checkWellFormedRecursionWalker((Node *) stmt->withClause->ctes,
00689 cstate);
00690 Assert(cstate->innerwiths == NIL);
00691 }
00692
00693
00694
00695
00696
00697
00698
00699
00700 if (stmt->sortClause)
00701 ereport(ERROR,
00702 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
00703 errmsg("ORDER BY in a recursive query is not implemented"),
00704 parser_errposition(cstate->pstate,
00705 exprLocation((Node *) stmt->sortClause))));
00706 if (stmt->limitOffset)
00707 ereport(ERROR,
00708 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
00709 errmsg("OFFSET in a recursive query is not implemented"),
00710 parser_errposition(cstate->pstate,
00711 exprLocation(stmt->limitOffset))));
00712 if (stmt->limitCount)
00713 ereport(ERROR,
00714 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
00715 errmsg("LIMIT in a recursive query is not implemented"),
00716 parser_errposition(cstate->pstate,
00717 exprLocation(stmt->limitCount))));
00718 if (stmt->lockingClause)
00719 ereport(ERROR,
00720 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
00721 errmsg("FOR UPDATE/SHARE in a recursive query is not implemented"),
00722 parser_errposition(cstate->pstate,
00723 exprLocation((Node *) stmt->lockingClause))));
00724 }
00725 }
00726
00727
00728
00729
00730 static bool
00731 checkWellFormedRecursionWalker(Node *node, CteState *cstate)
00732 {
00733 RecursionContext save_context = cstate->context;
00734
00735 if (node == NULL)
00736 return false;
00737 if (IsA(node, RangeVar))
00738 {
00739 RangeVar *rv = (RangeVar *) node;
00740
00741
00742 if (!rv->schemaname)
00743 {
00744 ListCell *lc;
00745 CommonTableExpr *mycte;
00746
00747
00748 foreach(lc, cstate->innerwiths)
00749 {
00750 List *withlist = (List *) lfirst(lc);
00751 ListCell *lc2;
00752
00753 foreach(lc2, withlist)
00754 {
00755 CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc2);
00756
00757 if (strcmp(rv->relname, cte->ctename) == 0)
00758 return false;
00759 }
00760 }
00761
00762
00763 mycte = cstate->items[cstate->curitem].cte;
00764 if (strcmp(rv->relname, mycte->ctename) == 0)
00765 {
00766
00767 if (cstate->context != RECURSION_OK)
00768 ereport(ERROR,
00769 (errcode(ERRCODE_INVALID_RECURSION),
00770 errmsg(recursion_errormsgs[cstate->context],
00771 mycte->ctename),
00772 parser_errposition(cstate->pstate,
00773 rv->location)));
00774
00775 if (++(cstate->selfrefcount) > 1)
00776 ereport(ERROR,
00777 (errcode(ERRCODE_INVALID_RECURSION),
00778 errmsg("recursive reference to query \"%s\" must not appear more than once",
00779 mycte->ctename),
00780 parser_errposition(cstate->pstate,
00781 rv->location)));
00782 }
00783 }
00784 return false;
00785 }
00786 if (IsA(node, SelectStmt))
00787 {
00788 SelectStmt *stmt = (SelectStmt *) node;
00789 ListCell *lc;
00790
00791 if (stmt->withClause)
00792 {
00793 if (stmt->withClause->recursive)
00794 {
00795
00796
00797
00798
00799
00800 cstate->innerwiths = lcons(stmt->withClause->ctes,
00801 cstate->innerwiths);
00802 foreach(lc, stmt->withClause->ctes)
00803 {
00804 CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc);
00805
00806 (void) checkWellFormedRecursionWalker(cte->ctequery, cstate);
00807 }
00808 checkWellFormedSelectStmt(stmt, cstate);
00809 cstate->innerwiths = list_delete_first(cstate->innerwiths);
00810 }
00811 else
00812 {
00813
00814
00815
00816
00817 ListCell *cell1;
00818
00819 cstate->innerwiths = lcons(NIL, cstate->innerwiths);
00820 cell1 = list_head(cstate->innerwiths);
00821 foreach(lc, stmt->withClause->ctes)
00822 {
00823 CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc);
00824
00825 (void) checkWellFormedRecursionWalker(cte->ctequery, cstate);
00826 lfirst(cell1) = lappend((List *) lfirst(cell1), cte);
00827 }
00828 checkWellFormedSelectStmt(stmt, cstate);
00829 cstate->innerwiths = list_delete_first(cstate->innerwiths);
00830 }
00831 }
00832 else
00833 checkWellFormedSelectStmt(stmt, cstate);
00834
00835 return false;
00836 }
00837 if (IsA(node, WithClause))
00838 {
00839
00840
00841
00842
00843
00844 return false;
00845 }
00846 if (IsA(node, JoinExpr))
00847 {
00848 JoinExpr *j = (JoinExpr *) node;
00849
00850 switch (j->jointype)
00851 {
00852 case JOIN_INNER:
00853 checkWellFormedRecursionWalker(j->larg, cstate);
00854 checkWellFormedRecursionWalker(j->rarg, cstate);
00855 checkWellFormedRecursionWalker(j->quals, cstate);
00856 break;
00857 case JOIN_LEFT:
00858 checkWellFormedRecursionWalker(j->larg, cstate);
00859 if (save_context == RECURSION_OK)
00860 cstate->context = RECURSION_OUTERJOIN;
00861 checkWellFormedRecursionWalker(j->rarg, cstate);
00862 cstate->context = save_context;
00863 checkWellFormedRecursionWalker(j->quals, cstate);
00864 break;
00865 case JOIN_FULL:
00866 if (save_context == RECURSION_OK)
00867 cstate->context = RECURSION_OUTERJOIN;
00868 checkWellFormedRecursionWalker(j->larg, cstate);
00869 checkWellFormedRecursionWalker(j->rarg, cstate);
00870 cstate->context = save_context;
00871 checkWellFormedRecursionWalker(j->quals, cstate);
00872 break;
00873 case JOIN_RIGHT:
00874 if (save_context == RECURSION_OK)
00875 cstate->context = RECURSION_OUTERJOIN;
00876 checkWellFormedRecursionWalker(j->larg, cstate);
00877 cstate->context = save_context;
00878 checkWellFormedRecursionWalker(j->rarg, cstate);
00879 checkWellFormedRecursionWalker(j->quals, cstate);
00880 break;
00881 default:
00882 elog(ERROR, "unrecognized join type: %d",
00883 (int) j->jointype);
00884 }
00885 return false;
00886 }
00887 if (IsA(node, SubLink))
00888 {
00889 SubLink *sl = (SubLink *) node;
00890
00891
00892
00893
00894
00895 cstate->context = RECURSION_SUBLINK;
00896 checkWellFormedRecursionWalker(sl->subselect, cstate);
00897 cstate->context = save_context;
00898 checkWellFormedRecursionWalker(sl->testexpr, cstate);
00899 return false;
00900 }
00901 return raw_expression_tree_walker(node,
00902 checkWellFormedRecursionWalker,
00903 (void *) cstate);
00904 }
00905
00906
00907
00908
00909
00910 static void
00911 checkWellFormedSelectStmt(SelectStmt *stmt, CteState *cstate)
00912 {
00913 RecursionContext save_context = cstate->context;
00914
00915 if (save_context != RECURSION_OK)
00916 {
00917
00918 raw_expression_tree_walker((Node *) stmt,
00919 checkWellFormedRecursionWalker,
00920 (void *) cstate);
00921 }
00922 else
00923 {
00924 switch (stmt->op)
00925 {
00926 case SETOP_NONE:
00927 case SETOP_UNION:
00928 raw_expression_tree_walker((Node *) stmt,
00929 checkWellFormedRecursionWalker,
00930 (void *) cstate);
00931 break;
00932 case SETOP_INTERSECT:
00933 if (stmt->all)
00934 cstate->context = RECURSION_INTERSECT;
00935 checkWellFormedRecursionWalker((Node *) stmt->larg,
00936 cstate);
00937 checkWellFormedRecursionWalker((Node *) stmt->rarg,
00938 cstate);
00939 cstate->context = save_context;
00940 checkWellFormedRecursionWalker((Node *) stmt->sortClause,
00941 cstate);
00942 checkWellFormedRecursionWalker((Node *) stmt->limitOffset,
00943 cstate);
00944 checkWellFormedRecursionWalker((Node *) stmt->limitCount,
00945 cstate);
00946 checkWellFormedRecursionWalker((Node *) stmt->lockingClause,
00947 cstate);
00948
00949 break;
00950 case SETOP_EXCEPT:
00951 if (stmt->all)
00952 cstate->context = RECURSION_EXCEPT;
00953 checkWellFormedRecursionWalker((Node *) stmt->larg,
00954 cstate);
00955 cstate->context = RECURSION_EXCEPT;
00956 checkWellFormedRecursionWalker((Node *) stmt->rarg,
00957 cstate);
00958 cstate->context = save_context;
00959 checkWellFormedRecursionWalker((Node *) stmt->sortClause,
00960 cstate);
00961 checkWellFormedRecursionWalker((Node *) stmt->limitOffset,
00962 cstate);
00963 checkWellFormedRecursionWalker((Node *) stmt->limitCount,
00964 cstate);
00965 checkWellFormedRecursionWalker((Node *) stmt->lockingClause,
00966 cstate);
00967
00968 break;
00969 default:
00970 elog(ERROR, "unrecognized set op: %d",
00971 (int) stmt->op);
00972 }
00973 }
00974 }