00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #include "postgres.h"
00015
00016 #include "access/sysattr.h"
00017 #include "catalog/pg_type.h"
00018 #include "commands/trigger.h"
00019 #include "foreign/fdwapi.h"
00020 #include "nodes/makefuncs.h"
00021 #include "nodes/nodeFuncs.h"
00022 #include "parser/analyze.h"
00023 #include "parser/parse_coerce.h"
00024 #include "parser/parsetree.h"
00025 #include "rewrite/rewriteDefine.h"
00026 #include "rewrite/rewriteHandler.h"
00027 #include "rewrite/rewriteManip.h"
00028 #include "utils/builtins.h"
00029 #include "utils/lsyscache.h"
00030 #include "utils/rel.h"
00031
00032
00033
00034 typedef struct rewrite_event
00035 {
00036 Oid relation;
00037 CmdType event;
00038 } rewrite_event;
00039
00040 static bool acquireLocksOnSubLinks(Node *node, void *context);
00041 static Query *rewriteRuleAction(Query *parsetree,
00042 Query *rule_action,
00043 Node *rule_qual,
00044 int rt_index,
00045 CmdType event,
00046 bool *returning_flag);
00047 static List *adjustJoinTreeList(Query *parsetree, bool removert, int rt_index);
00048 static void rewriteTargetListIU(Query *parsetree, Relation target_relation,
00049 List **attrno_list);
00050 static TargetEntry *process_matched_tle(TargetEntry *src_tle,
00051 TargetEntry *prior_tle,
00052 const char *attrName);
00053 static Node *get_assignment_input(Node *node);
00054 static void rewriteValuesRTE(RangeTblEntry *rte, Relation target_relation,
00055 List *attrnos);
00056 static void rewriteTargetListUD(Query *parsetree, RangeTblEntry *target_rte,
00057 Relation target_relation);
00058 static void markQueryForLocking(Query *qry, Node *jtnode,
00059 LockClauseStrength strength, bool noWait, bool pushedDown);
00060 static List *matchLocks(CmdType event, RuleLock *rulelocks,
00061 int varno, Query *parsetree);
00062 static Query *fireRIRrules(Query *parsetree, List *activeRIRs,
00063 bool forUpdatePushedDown);
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102 void
00103 AcquireRewriteLocks(Query *parsetree, bool forUpdatePushedDown)
00104 {
00105 ListCell *l;
00106 int rt_index;
00107
00108
00109
00110
00111 rt_index = 0;
00112 foreach(l, parsetree->rtable)
00113 {
00114 RangeTblEntry *rte = (RangeTblEntry *) lfirst(l);
00115 Relation rel;
00116 LOCKMODE lockmode;
00117 List *newaliasvars;
00118 Index curinputvarno;
00119 RangeTblEntry *curinputrte;
00120 ListCell *ll;
00121
00122 ++rt_index;
00123 switch (rte->rtekind)
00124 {
00125 case RTE_RELATION:
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139 if (rt_index == parsetree->resultRelation)
00140 lockmode = RowExclusiveLock;
00141 else if (forUpdatePushedDown ||
00142 get_parse_rowmark(parsetree, rt_index) != NULL)
00143 lockmode = RowShareLock;
00144 else
00145 lockmode = AccessShareLock;
00146
00147 rel = heap_open(rte->relid, lockmode);
00148
00149
00150
00151
00152
00153 rte->relkind = rel->rd_rel->relkind;
00154
00155 heap_close(rel, NoLock);
00156 break;
00157
00158 case RTE_JOIN:
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169 newaliasvars = NIL;
00170 curinputvarno = 0;
00171 curinputrte = NULL;
00172 foreach(ll, rte->joinaliasvars)
00173 {
00174 Var *aliasvar = (Var *) lfirst(ll);
00175
00176
00177
00178
00179
00180
00181
00182
00183 if (IsA(aliasvar, Var))
00184 {
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194 Assert(aliasvar->varlevelsup == 0);
00195 if (aliasvar->varno != curinputvarno)
00196 {
00197 curinputvarno = aliasvar->varno;
00198 if (curinputvarno >= rt_index)
00199 elog(ERROR, "unexpected varno %d in JOIN RTE %d",
00200 curinputvarno, rt_index);
00201 curinputrte = rt_fetch(curinputvarno,
00202 parsetree->rtable);
00203 }
00204 if (get_rte_attribute_is_dropped(curinputrte,
00205 aliasvar->varattno))
00206 {
00207
00208
00209
00210
00211
00212 aliasvar = (Var *) makeNullConst(INT4OID, -1, InvalidOid);
00213 }
00214 }
00215 newaliasvars = lappend(newaliasvars, aliasvar);
00216 }
00217 rte->joinaliasvars = newaliasvars;
00218 break;
00219
00220 case RTE_SUBQUERY:
00221
00222
00223
00224
00225
00226 AcquireRewriteLocks(rte->subquery,
00227 (forUpdatePushedDown ||
00228 get_parse_rowmark(parsetree, rt_index) != NULL));
00229 break;
00230
00231 default:
00232
00233 break;
00234 }
00235 }
00236
00237
00238 foreach(l, parsetree->cteList)
00239 {
00240 CommonTableExpr *cte = (CommonTableExpr *) lfirst(l);
00241
00242 AcquireRewriteLocks((Query *) cte->ctequery, false);
00243 }
00244
00245
00246
00247
00248
00249 if (parsetree->hasSubLinks)
00250 query_tree_walker(parsetree, acquireLocksOnSubLinks, NULL,
00251 QTW_IGNORE_RC_SUBQUERIES);
00252 }
00253
00254
00255
00256
00257 static bool
00258 acquireLocksOnSubLinks(Node *node, void *context)
00259 {
00260 if (node == NULL)
00261 return false;
00262 if (IsA(node, SubLink))
00263 {
00264 SubLink *sub = (SubLink *) node;
00265
00266
00267 AcquireRewriteLocks((Query *) sub->subselect, false);
00268
00269 }
00270
00271
00272
00273
00274
00275 return expression_tree_walker(node, acquireLocksOnSubLinks, context);
00276 }
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296 static Query *
00297 rewriteRuleAction(Query *parsetree,
00298 Query *rule_action,
00299 Node *rule_qual,
00300 int rt_index,
00301 CmdType event,
00302 bool *returning_flag)
00303 {
00304 int current_varno,
00305 new_varno;
00306 int rt_length;
00307 Query *sub_action;
00308 Query **sub_action_ptr;
00309
00310
00311
00312
00313
00314 rule_action = (Query *) copyObject(rule_action);
00315 rule_qual = (Node *) copyObject(rule_qual);
00316
00317
00318
00319
00320 AcquireRewriteLocks(rule_action, false);
00321 (void) acquireLocksOnSubLinks(rule_qual, NULL);
00322
00323 current_varno = rt_index;
00324 rt_length = list_length(parsetree->rtable);
00325 new_varno = PRS2_NEW_VARNO + rt_length;
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335 sub_action = getInsertSelectQuery(rule_action, &sub_action_ptr);
00336
00337 OffsetVarNodes((Node *) sub_action, rt_length, 0);
00338 OffsetVarNodes(rule_qual, rt_length, 0);
00339
00340 ChangeVarNodes((Node *) sub_action,
00341 PRS2_OLD_VARNO + rt_length, rt_index, 0);
00342 ChangeVarNodes(rule_qual,
00343 PRS2_OLD_VARNO + rt_length, rt_index, 0);
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373 sub_action->rtable = list_concat((List *) copyObject(parsetree->rtable),
00374 sub_action->rtable);
00375
00376
00377
00378
00379
00380 if (parsetree->hasSubLinks && !sub_action->hasSubLinks)
00381 {
00382 ListCell *lc;
00383
00384 foreach(lc, parsetree->rtable)
00385 {
00386 RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
00387
00388 switch (rte->rtekind)
00389 {
00390 case RTE_FUNCTION:
00391 sub_action->hasSubLinks =
00392 checkExprHasSubLink(rte->funcexpr);
00393 break;
00394 case RTE_VALUES:
00395 sub_action->hasSubLinks =
00396 checkExprHasSubLink((Node *) rte->values_lists);
00397 break;
00398 default:
00399
00400 break;
00401 }
00402 if (sub_action->hasSubLinks)
00403 break;
00404 }
00405 }
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421 if (sub_action->commandType != CMD_UTILITY)
00422 {
00423 bool keeporig;
00424 List *newjointree;
00425
00426 Assert(sub_action->jointree != NULL);
00427 keeporig = (!rangeTableEntry_used((Node *) sub_action->jointree,
00428 rt_index, 0)) &&
00429 (rangeTableEntry_used(rule_qual, rt_index, 0) ||
00430 rangeTableEntry_used(parsetree->jointree->quals, rt_index, 0));
00431 newjointree = adjustJoinTreeList(parsetree, !keeporig, rt_index);
00432 if (newjointree != NIL)
00433 {
00434
00435
00436
00437
00438
00439
00440 if (sub_action->setOperations != NULL)
00441 ereport(ERROR,
00442 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
00443 errmsg("conditional UNION/INTERSECT/EXCEPT statements are not implemented")));
00444
00445 sub_action->jointree->fromlist =
00446 list_concat(newjointree, sub_action->jointree->fromlist);
00447
00448
00449
00450
00451
00452 if (parsetree->hasSubLinks && !sub_action->hasSubLinks)
00453 sub_action->hasSubLinks =
00454 checkExprHasSubLink((Node *) newjointree);
00455 }
00456 }
00457
00458
00459
00460
00461
00462 if (parsetree->cteList != NIL && sub_action->commandType != CMD_UTILITY)
00463 {
00464 ListCell *lc;
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474 foreach(lc, parsetree->cteList)
00475 {
00476 CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc);
00477 ListCell *lc2;
00478
00479 foreach(lc2, sub_action->cteList)
00480 {
00481 CommonTableExpr *cte2 = (CommonTableExpr *) lfirst(lc2);
00482
00483 if (strcmp(cte->ctename, cte2->ctename) == 0)
00484 ereport(ERROR,
00485 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
00486 errmsg("WITH query name \"%s\" appears in both a rule action and the query being rewritten",
00487 cte->ctename)));
00488 }
00489 }
00490
00491
00492 sub_action->cteList = list_concat(sub_action->cteList,
00493 copyObject(parsetree->cteList));
00494 }
00495
00496
00497
00498
00499
00500
00501 AddQual(sub_action, rule_qual);
00502
00503 AddQual(sub_action, parsetree->jointree->quals);
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513 if ((event == CMD_INSERT || event == CMD_UPDATE) &&
00514 sub_action->commandType != CMD_UTILITY)
00515 {
00516 sub_action = (Query *)
00517 ReplaceVarsFromTargetList((Node *) sub_action,
00518 new_varno,
00519 0,
00520 rt_fetch(new_varno, sub_action->rtable),
00521 parsetree->targetList,
00522 (event == CMD_UPDATE) ?
00523 REPLACEVARS_CHANGE_VARNO :
00524 REPLACEVARS_SUBSTITUTE_NULL,
00525 current_varno,
00526 NULL);
00527 if (sub_action_ptr)
00528 *sub_action_ptr = sub_action;
00529 else
00530 rule_action = sub_action;
00531 }
00532
00533
00534
00535
00536
00537
00538
00539 if (!parsetree->returningList)
00540 rule_action->returningList = NIL;
00541 else if (rule_action->returningList)
00542 {
00543 if (*returning_flag)
00544 ereport(ERROR,
00545 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
00546 errmsg("cannot have RETURNING lists in multiple rules")));
00547 *returning_flag = true;
00548 rule_action->returningList = (List *)
00549 ReplaceVarsFromTargetList((Node *) parsetree->returningList,
00550 parsetree->resultRelation,
00551 0,
00552 rt_fetch(parsetree->resultRelation,
00553 parsetree->rtable),
00554 rule_action->returningList,
00555 REPLACEVARS_REPORT_ERROR,
00556 0,
00557 &rule_action->hasSubLinks);
00558
00559
00560
00561
00562
00563 if (parsetree->hasSubLinks && !rule_action->hasSubLinks)
00564 rule_action->hasSubLinks =
00565 checkExprHasSubLink((Node *) rule_action->returningList);
00566 }
00567
00568 return rule_action;
00569 }
00570
00571
00572
00573
00574
00575
00576
00577
00578
00579 static List *
00580 adjustJoinTreeList(Query *parsetree, bool removert, int rt_index)
00581 {
00582 List *newjointree = copyObject(parsetree->jointree->fromlist);
00583 ListCell *l;
00584
00585 if (removert)
00586 {
00587 foreach(l, newjointree)
00588 {
00589 RangeTblRef *rtr = lfirst(l);
00590
00591 if (IsA(rtr, RangeTblRef) &&
00592 rtr->rtindex == rt_index)
00593 {
00594 newjointree = list_delete_ptr(newjointree, rtr);
00595
00596
00597
00598
00599 break;
00600 }
00601 }
00602 }
00603 return newjointree;
00604 }
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614
00615
00616
00617
00618
00619
00620
00621
00622
00623
00624
00625
00626
00627
00628
00629
00630
00631
00632
00633
00634
00635
00636
00637
00638
00639
00640
00641
00642
00643
00644
00645
00646
00647
00648 static void
00649 rewriteTargetListIU(Query *parsetree, Relation target_relation,
00650 List **attrno_list)
00651 {
00652 CmdType commandType = parsetree->commandType;
00653 TargetEntry **new_tles;
00654 List *new_tlist = NIL;
00655 List *junk_tlist = NIL;
00656 Form_pg_attribute att_tup;
00657 int attrno,
00658 next_junk_attrno,
00659 numattrs;
00660 ListCell *temp;
00661
00662 if (attrno_list)
00663 *attrno_list = NIL;
00664
00665
00666
00667
00668
00669
00670
00671
00672
00673
00674 numattrs = RelationGetNumberOfAttributes(target_relation);
00675 new_tles = (TargetEntry **) palloc0(numattrs * sizeof(TargetEntry *));
00676 next_junk_attrno = numattrs + 1;
00677
00678 foreach(temp, parsetree->targetList)
00679 {
00680 TargetEntry *old_tle = (TargetEntry *) lfirst(temp);
00681
00682 if (!old_tle->resjunk)
00683 {
00684
00685 attrno = old_tle->resno;
00686 if (attrno < 1 || attrno > numattrs)
00687 elog(ERROR, "bogus resno %d in targetlist", attrno);
00688 att_tup = target_relation->rd_att->attrs[attrno - 1];
00689
00690
00691 if (attrno_list)
00692 *attrno_list = lappend_int(*attrno_list, attrno);
00693
00694
00695 if (att_tup->attisdropped)
00696 continue;
00697
00698
00699 new_tles[attrno - 1] =
00700 process_matched_tle(old_tle,
00701 new_tles[attrno - 1],
00702 NameStr(att_tup->attname));
00703 }
00704 else
00705 {
00706
00707
00708
00709
00710
00711
00712
00713
00714
00715
00716 if (old_tle->resno != next_junk_attrno)
00717 {
00718 old_tle = flatCopyTargetEntry(old_tle);
00719 old_tle->resno = next_junk_attrno;
00720 }
00721 junk_tlist = lappend(junk_tlist, old_tle);
00722 next_junk_attrno++;
00723 }
00724 }
00725
00726 for (attrno = 1; attrno <= numattrs; attrno++)
00727 {
00728 TargetEntry *new_tle = new_tles[attrno - 1];
00729
00730 att_tup = target_relation->rd_att->attrs[attrno - 1];
00731
00732
00733 if (att_tup->attisdropped)
00734 continue;
00735
00736
00737
00738
00739
00740
00741 if ((new_tle == NULL && commandType == CMD_INSERT) ||
00742 (new_tle && new_tle->expr && IsA(new_tle->expr, SetToDefault)))
00743 {
00744 Node *new_expr;
00745
00746 new_expr = build_column_default(target_relation, attrno);
00747
00748
00749
00750
00751
00752
00753
00754
00755 if (!new_expr)
00756 {
00757 if (commandType == CMD_INSERT)
00758 new_tle = NULL;
00759 else
00760 {
00761 new_expr = (Node *) makeConst(att_tup->atttypid,
00762 -1,
00763 att_tup->attcollation,
00764 att_tup->attlen,
00765 (Datum) 0,
00766 true,
00767 att_tup->attbyval);
00768
00769 new_expr = coerce_to_domain(new_expr,
00770 InvalidOid, -1,
00771 att_tup->atttypid,
00772 COERCE_IMPLICIT_CAST,
00773 -1,
00774 false,
00775 false);
00776 }
00777 }
00778
00779 if (new_expr)
00780 new_tle = makeTargetEntry((Expr *) new_expr,
00781 attrno,
00782 pstrdup(NameStr(att_tup->attname)),
00783 false);
00784 }
00785
00786
00787
00788
00789
00790 if (new_tle == NULL && commandType == CMD_UPDATE &&
00791 target_relation->rd_rel->relkind == RELKIND_VIEW)
00792 {
00793 Node *new_expr;
00794
00795 new_expr = (Node *) makeVar(parsetree->resultRelation,
00796 attrno,
00797 att_tup->atttypid,
00798 att_tup->atttypmod,
00799 att_tup->attcollation,
00800 0);
00801
00802 new_tle = makeTargetEntry((Expr *) new_expr,
00803 attrno,
00804 pstrdup(NameStr(att_tup->attname)),
00805 false);
00806 }
00807
00808 if (new_tle)
00809 new_tlist = lappend(new_tlist, new_tle);
00810 }
00811
00812 pfree(new_tles);
00813
00814 parsetree->targetList = list_concat(new_tlist, junk_tlist);
00815 }
00816
00817
00818
00819
00820
00821
00822
00823
00824 static TargetEntry *
00825 process_matched_tle(TargetEntry *src_tle,
00826 TargetEntry *prior_tle,
00827 const char *attrName)
00828 {
00829 TargetEntry *result;
00830 Node *src_expr;
00831 Node *prior_expr;
00832 Node *src_input;
00833 Node *prior_input;
00834 Node *priorbottom;
00835 Node *newexpr;
00836
00837 if (prior_tle == NULL)
00838 {
00839
00840
00841
00842 return src_tle;
00843 }
00844
00845
00846
00847
00848
00849
00850
00851
00852
00853
00854
00855
00856
00857
00858
00859
00860
00861
00862
00863
00864
00865
00866
00867
00868 src_expr = (Node *) src_tle->expr;
00869 prior_expr = (Node *) prior_tle->expr;
00870 src_input = get_assignment_input(src_expr);
00871 prior_input = get_assignment_input(prior_expr);
00872 if (src_input == NULL ||
00873 prior_input == NULL ||
00874 exprType(src_expr) != exprType(prior_expr))
00875 ereport(ERROR,
00876 (errcode(ERRCODE_SYNTAX_ERROR),
00877 errmsg("multiple assignments to same column \"%s\"",
00878 attrName)));
00879
00880
00881
00882
00883 priorbottom = prior_input;
00884 for (;;)
00885 {
00886 Node *newbottom = get_assignment_input(priorbottom);
00887
00888 if (newbottom == NULL)
00889 break;
00890 priorbottom = newbottom;
00891 }
00892 if (!equal(priorbottom, src_input))
00893 ereport(ERROR,
00894 (errcode(ERRCODE_SYNTAX_ERROR),
00895 errmsg("multiple assignments to same column \"%s\"",
00896 attrName)));
00897
00898
00899
00900
00901 if (IsA(src_expr, FieldStore))
00902 {
00903 FieldStore *fstore = makeNode(FieldStore);
00904
00905 if (IsA(prior_expr, FieldStore))
00906 {
00907
00908 memcpy(fstore, prior_expr, sizeof(FieldStore));
00909 fstore->newvals =
00910 list_concat(list_copy(((FieldStore *) prior_expr)->newvals),
00911 list_copy(((FieldStore *) src_expr)->newvals));
00912 fstore->fieldnums =
00913 list_concat(list_copy(((FieldStore *) prior_expr)->fieldnums),
00914 list_copy(((FieldStore *) src_expr)->fieldnums));
00915 }
00916 else
00917 {
00918
00919 memcpy(fstore, src_expr, sizeof(FieldStore));
00920 fstore->arg = (Expr *) prior_expr;
00921 }
00922 newexpr = (Node *) fstore;
00923 }
00924 else if (IsA(src_expr, ArrayRef))
00925 {
00926 ArrayRef *aref = makeNode(ArrayRef);
00927
00928 memcpy(aref, src_expr, sizeof(ArrayRef));
00929 aref->refexpr = (Expr *) prior_expr;
00930 newexpr = (Node *) aref;
00931 }
00932 else
00933 {
00934 elog(ERROR, "cannot happen");
00935 newexpr = NULL;
00936 }
00937
00938 result = flatCopyTargetEntry(src_tle);
00939 result->expr = (Expr *) newexpr;
00940 return result;
00941 }
00942
00943
00944
00945
00946 static Node *
00947 get_assignment_input(Node *node)
00948 {
00949 if (node == NULL)
00950 return NULL;
00951 if (IsA(node, FieldStore))
00952 {
00953 FieldStore *fstore = (FieldStore *) node;
00954
00955 return (Node *) fstore->arg;
00956 }
00957 else if (IsA(node, ArrayRef))
00958 {
00959 ArrayRef *aref = (ArrayRef *) node;
00960
00961 if (aref->refassgnexpr == NULL)
00962 return NULL;
00963 return (Node *) aref->refexpr;
00964 }
00965 return NULL;
00966 }
00967
00968
00969
00970
00971
00972
00973 Node *
00974 build_column_default(Relation rel, int attrno)
00975 {
00976 TupleDesc rd_att = rel->rd_att;
00977 Form_pg_attribute att_tup = rd_att->attrs[attrno - 1];
00978 Oid atttype = att_tup->atttypid;
00979 int32 atttypmod = att_tup->atttypmod;
00980 Node *expr = NULL;
00981 Oid exprtype;
00982
00983
00984
00985
00986 if (rd_att->constr && rd_att->constr->num_defval > 0)
00987 {
00988 AttrDefault *defval = rd_att->constr->defval;
00989 int ndef = rd_att->constr->num_defval;
00990
00991 while (--ndef >= 0)
00992 {
00993 if (attrno == defval[ndef].adnum)
00994 {
00995
00996
00997
00998 expr = stringToNode(defval[ndef].adbin);
00999 break;
01000 }
01001 }
01002 }
01003
01004 if (expr == NULL)
01005 {
01006
01007
01008
01009 expr = get_typdefault(atttype);
01010 }
01011
01012 if (expr == NULL)
01013 return NULL;
01014
01015
01016
01017
01018
01019
01020
01021
01022 exprtype = exprType(expr);
01023
01024 expr = coerce_to_target_type(NULL,
01025 expr, exprtype,
01026 atttype, atttypmod,
01027 COERCION_ASSIGNMENT,
01028 COERCE_IMPLICIT_CAST,
01029 -1);
01030 if (expr == NULL)
01031 ereport(ERROR,
01032 (errcode(ERRCODE_DATATYPE_MISMATCH),
01033 errmsg("column \"%s\" is of type %s"
01034 " but default expression is of type %s",
01035 NameStr(att_tup->attname),
01036 format_type_be(atttype),
01037 format_type_be(exprtype)),
01038 errhint("You will need to rewrite or cast the expression.")));
01039
01040 return expr;
01041 }
01042
01043
01044
01045 static bool
01046 searchForDefault(RangeTblEntry *rte)
01047 {
01048 ListCell *lc;
01049
01050 foreach(lc, rte->values_lists)
01051 {
01052 List *sublist = (List *) lfirst(lc);
01053 ListCell *lc2;
01054
01055 foreach(lc2, sublist)
01056 {
01057 Node *col = (Node *) lfirst(lc2);
01058
01059 if (IsA(col, SetToDefault))
01060 return true;
01061 }
01062 }
01063 return false;
01064 }
01065
01066
01067
01068
01069
01070
01071
01072
01073
01074
01075
01076
01077 static void
01078 rewriteValuesRTE(RangeTblEntry *rte, Relation target_relation, List *attrnos)
01079 {
01080 List *newValues;
01081 ListCell *lc;
01082
01083
01084
01085
01086
01087
01088 if (!searchForDefault(rte))
01089 return;
01090
01091
01092 Assert(list_length(attrnos) == list_length(linitial(rte->values_lists)));
01093
01094 newValues = NIL;
01095 foreach(lc, rte->values_lists)
01096 {
01097 List *sublist = (List *) lfirst(lc);
01098 List *newList = NIL;
01099 ListCell *lc2;
01100 ListCell *lc3;
01101
01102 forboth(lc2, sublist, lc3, attrnos)
01103 {
01104 Node *col = (Node *) lfirst(lc2);
01105 int attrno = lfirst_int(lc3);
01106
01107 if (IsA(col, SetToDefault))
01108 {
01109 Form_pg_attribute att_tup;
01110 Node *new_expr;
01111
01112 att_tup = target_relation->rd_att->attrs[attrno - 1];
01113
01114 if (!att_tup->attisdropped)
01115 new_expr = build_column_default(target_relation, attrno);
01116 else
01117 new_expr = NULL;
01118
01119
01120
01121
01122
01123 if (!new_expr)
01124 {
01125 new_expr = (Node *) makeConst(att_tup->atttypid,
01126 -1,
01127 att_tup->attcollation,
01128 att_tup->attlen,
01129 (Datum) 0,
01130 true,
01131 att_tup->attbyval);
01132
01133 new_expr = coerce_to_domain(new_expr,
01134 InvalidOid, -1,
01135 att_tup->atttypid,
01136 COERCE_IMPLICIT_CAST,
01137 -1,
01138 false,
01139 false);
01140 }
01141 newList = lappend(newList, new_expr);
01142 }
01143 else
01144 newList = lappend(newList, col);
01145 }
01146 newValues = lappend(newValues, newList);
01147 }
01148 rte->values_lists = newValues;
01149 }
01150
01151
01152
01153
01154
01155
01156
01157
01158
01159
01160
01161
01162
01163
01164
01165 static void
01166 rewriteTargetListUD(Query *parsetree, RangeTblEntry *target_rte,
01167 Relation target_relation)
01168 {
01169 Var *var;
01170 const char *attrname;
01171 TargetEntry *tle;
01172
01173 if (target_relation->rd_rel->relkind == RELKIND_RELATION ||
01174 target_relation->rd_rel->relkind == RELKIND_MATVIEW)
01175 {
01176
01177
01178
01179 var = makeVar(parsetree->resultRelation,
01180 SelfItemPointerAttributeNumber,
01181 TIDOID,
01182 -1,
01183 InvalidOid,
01184 0);
01185
01186 attrname = "ctid";
01187 }
01188 else if (target_relation->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
01189 {
01190
01191
01192
01193 FdwRoutine *fdwroutine;
01194
01195 fdwroutine = GetFdwRoutineForRelation(target_relation, false);
01196
01197 if (fdwroutine->AddForeignUpdateTargets != NULL)
01198 fdwroutine->AddForeignUpdateTargets(parsetree, target_rte,
01199 target_relation);
01200
01201 return;
01202 }
01203 else
01204 {
01205
01206
01207
01208
01209 var = makeWholeRowVar(target_rte,
01210 parsetree->resultRelation,
01211 0,
01212 false);
01213
01214 attrname = "wholerow";
01215 }
01216
01217 tle = makeTargetEntry((Expr *) var,
01218 list_length(parsetree->targetList) + 1,
01219 pstrdup(attrname),
01220 true);
01221
01222 parsetree->targetList = lappend(parsetree->targetList, tle);
01223 }
01224
01225
01226
01227
01228
01229
01230 static List *
01231 matchLocks(CmdType event,
01232 RuleLock *rulelocks,
01233 int varno,
01234 Query *parsetree)
01235 {
01236 List *matching_locks = NIL;
01237 int nlocks;
01238 int i;
01239
01240 if (rulelocks == NULL)
01241 return NIL;
01242
01243 if (parsetree->commandType != CMD_SELECT)
01244 {
01245 if (parsetree->resultRelation != varno)
01246 return NIL;
01247 }
01248
01249 nlocks = rulelocks->numLocks;
01250
01251 for (i = 0; i < nlocks; i++)
01252 {
01253 RewriteRule *oneLock = rulelocks->rules[i];
01254
01255
01256
01257
01258
01259
01260
01261 if (oneLock->event != CMD_SELECT)
01262 {
01263 if (SessionReplicationRole == SESSION_REPLICATION_ROLE_REPLICA)
01264 {
01265 if (oneLock->enabled == RULE_FIRES_ON_ORIGIN ||
01266 oneLock->enabled == RULE_DISABLED)
01267 continue;
01268 }
01269 else
01270 {
01271 if (oneLock->enabled == RULE_FIRES_ON_REPLICA ||
01272 oneLock->enabled == RULE_DISABLED)
01273 continue;
01274 }
01275 }
01276
01277 if (oneLock->event == event)
01278 {
01279 if (parsetree->commandType != CMD_SELECT ||
01280 (oneLock->attrno == -1 ?
01281 rangeTableEntry_used((Node *) parsetree, varno, 0) :
01282 attribute_used((Node *) parsetree,
01283 varno, oneLock->attrno, 0)))
01284 matching_locks = lappend(matching_locks, oneLock);
01285 }
01286 }
01287
01288 return matching_locks;
01289 }
01290
01291
01292
01293
01294
01295 static Query *
01296 ApplyRetrieveRule(Query *parsetree,
01297 RewriteRule *rule,
01298 int rt_index,
01299 bool relation_level,
01300 Relation relation,
01301 List *activeRIRs,
01302 bool forUpdatePushedDown)
01303 {
01304 Query *rule_action;
01305 RangeTblEntry *rte,
01306 *subrte;
01307 RowMarkClause *rc;
01308
01309 if (list_length(rule->actions) != 1)
01310 elog(ERROR, "expected just one rule action");
01311 if (rule->qual != NULL)
01312 elog(ERROR, "cannot handle qualified ON SELECT rule");
01313 if (!relation_level)
01314 elog(ERROR, "cannot handle per-attribute ON SELECT rule");
01315
01316 if (rt_index == parsetree->resultRelation)
01317 {
01318
01319
01320
01321
01322
01323
01324
01325
01326
01327
01328
01329
01330
01331
01332
01333
01334
01335 if (parsetree->commandType == CMD_INSERT)
01336 return parsetree;
01337 else if (parsetree->commandType == CMD_UPDATE ||
01338 parsetree->commandType == CMD_DELETE)
01339 {
01340 RangeTblEntry *newrte;
01341
01342 rte = rt_fetch(rt_index, parsetree->rtable);
01343 newrte = copyObject(rte);
01344 parsetree->rtable = lappend(parsetree->rtable, newrte);
01345 parsetree->resultRelation = list_length(parsetree->rtable);
01346
01347
01348
01349
01350
01351
01352 rte->requiredPerms = 0;
01353 rte->checkAsUser = InvalidOid;
01354 rte->selectedCols = NULL;
01355 rte->modifiedCols = NULL;
01356
01357
01358
01359
01360
01361
01362
01363
01364
01365
01366 parsetree->returningList = copyObject(parsetree->returningList);
01367 ChangeVarNodes((Node *) parsetree->returningList, rt_index,
01368 parsetree->resultRelation, 0);
01369
01370
01371 }
01372 else
01373 elog(ERROR, "unrecognized commandType: %d",
01374 (int) parsetree->commandType);
01375 }
01376
01377
01378
01379
01380
01381 rc = get_parse_rowmark(parsetree, rt_index);
01382 forUpdatePushedDown |= (rc != NULL);
01383
01384
01385
01386
01387
01388 rule_action = copyObject(linitial(rule->actions));
01389
01390 AcquireRewriteLocks(rule_action, forUpdatePushedDown);
01391
01392
01393
01394
01395 rule_action = fireRIRrules(rule_action, activeRIRs, forUpdatePushedDown);
01396
01397
01398
01399
01400
01401 rte = rt_fetch(rt_index, parsetree->rtable);
01402
01403 rte->rtekind = RTE_SUBQUERY;
01404 rte->relid = InvalidOid;
01405 rte->security_barrier = RelationIsSecurityView(relation);
01406 rte->subquery = rule_action;
01407 rte->inh = false;
01408
01409
01410
01411
01412
01413 subrte = rt_fetch(PRS2_OLD_VARNO, rule_action->rtable);
01414 Assert(subrte->relid == relation->rd_id);
01415 subrte->requiredPerms = rte->requiredPerms;
01416 subrte->checkAsUser = rte->checkAsUser;
01417 subrte->selectedCols = rte->selectedCols;
01418 subrte->modifiedCols = rte->modifiedCols;
01419
01420 rte->requiredPerms = 0;
01421 rte->checkAsUser = InvalidOid;
01422 rte->selectedCols = NULL;
01423 rte->modifiedCols = NULL;
01424
01425
01426
01427
01428
01429
01430
01431
01432
01433 if (rc != NULL)
01434 markQueryForLocking(rule_action, (Node *) rule_action->jointree,
01435 rc->strength, rc->noWait, true);
01436
01437 return parsetree;
01438 }
01439
01440
01441
01442
01443
01444
01445
01446
01447
01448
01449
01450
01451 static void
01452 markQueryForLocking(Query *qry, Node *jtnode,
01453 LockClauseStrength strength, bool noWait, bool pushedDown)
01454 {
01455 if (jtnode == NULL)
01456 return;
01457 if (IsA(jtnode, RangeTblRef))
01458 {
01459 int rti = ((RangeTblRef *) jtnode)->rtindex;
01460 RangeTblEntry *rte = rt_fetch(rti, qry->rtable);
01461
01462 if (rte->rtekind == RTE_RELATION)
01463 {
01464 applyLockingClause(qry, rti, strength, noWait, pushedDown);
01465 rte->requiredPerms |= ACL_SELECT_FOR_UPDATE;
01466 }
01467 else if (rte->rtekind == RTE_SUBQUERY)
01468 {
01469 applyLockingClause(qry, rti, strength, noWait, pushedDown);
01470
01471 markQueryForLocking(rte->subquery, (Node *) rte->subquery->jointree,
01472 strength, noWait, true);
01473 }
01474
01475 }
01476 else if (IsA(jtnode, FromExpr))
01477 {
01478 FromExpr *f = (FromExpr *) jtnode;
01479 ListCell *l;
01480
01481 foreach(l, f->fromlist)
01482 markQueryForLocking(qry, lfirst(l), strength, noWait, pushedDown);
01483 }
01484 else if (IsA(jtnode, JoinExpr))
01485 {
01486 JoinExpr *j = (JoinExpr *) jtnode;
01487
01488 markQueryForLocking(qry, j->larg, strength, noWait, pushedDown);
01489 markQueryForLocking(qry, j->rarg, strength, noWait, pushedDown);
01490 }
01491 else
01492 elog(ERROR, "unrecognized node type: %d",
01493 (int) nodeTag(jtnode));
01494 }
01495
01496
01497
01498
01499
01500
01501
01502
01503
01504
01505
01506
01507
01508
01509
01510 static bool
01511 fireRIRonSubLink(Node *node, List *activeRIRs)
01512 {
01513 if (node == NULL)
01514 return false;
01515 if (IsA(node, SubLink))
01516 {
01517 SubLink *sub = (SubLink *) node;
01518
01519
01520 sub->subselect = (Node *) fireRIRrules((Query *) sub->subselect,
01521 activeRIRs, false);
01522
01523 }
01524
01525
01526
01527
01528
01529 return expression_tree_walker(node, fireRIRonSubLink,
01530 (void *) activeRIRs);
01531 }
01532
01533
01534
01535
01536
01537
01538 static Query *
01539 fireRIRrules(Query *parsetree, List *activeRIRs, bool forUpdatePushedDown)
01540 {
01541 int origResultRelation = parsetree->resultRelation;
01542 int rt_index;
01543 ListCell *lc;
01544
01545
01546
01547
01548
01549 rt_index = 0;
01550 while (rt_index < list_length(parsetree->rtable))
01551 {
01552 RangeTblEntry *rte;
01553 Relation rel;
01554 List *locks;
01555 RuleLock *rules;
01556 RewriteRule *rule;
01557 int i;
01558
01559 ++rt_index;
01560
01561 rte = rt_fetch(rt_index, parsetree->rtable);
01562
01563
01564
01565
01566
01567
01568 if (rte->rtekind == RTE_SUBQUERY)
01569 {
01570 rte->subquery = fireRIRrules(rte->subquery, activeRIRs,
01571 (forUpdatePushedDown ||
01572 get_parse_rowmark(parsetree, rt_index) != NULL));
01573 continue;
01574 }
01575
01576
01577
01578
01579 if (rte->rtekind != RTE_RELATION)
01580 continue;
01581
01582
01583
01584
01585
01586
01587
01588
01589
01590
01591
01592 if (rte->relkind == RELKIND_MATVIEW)
01593 continue;
01594
01595
01596
01597
01598
01599
01600
01601
01602 if (rt_index != parsetree->resultRelation &&
01603 !rangeTableEntry_used((Node *) parsetree, rt_index, 0))
01604 continue;
01605
01606
01607
01608
01609
01610 if (rt_index == parsetree->resultRelation &&
01611 rt_index != origResultRelation)
01612 continue;
01613
01614
01615
01616
01617
01618 rel = heap_open(rte->relid, NoLock);
01619
01620
01621
01622
01623 rules = rel->rd_rules;
01624 if (rules == NULL)
01625 {
01626 heap_close(rel, NoLock);
01627 continue;
01628 }
01629 locks = NIL;
01630 for (i = 0; i < rules->numLocks; i++)
01631 {
01632 rule = rules->rules[i];
01633 if (rule->event != CMD_SELECT)
01634 continue;
01635
01636 if (rule->attrno > 0)
01637 {
01638
01639 if (!attribute_used((Node *) parsetree, rt_index,
01640 rule->attrno, 0))
01641 continue;
01642 }
01643
01644 locks = lappend(locks, rule);
01645 }
01646
01647
01648
01649
01650 if (locks != NIL)
01651 {
01652 ListCell *l;
01653
01654 if (list_member_oid(activeRIRs, RelationGetRelid(rel)))
01655 ereport(ERROR,
01656 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
01657 errmsg("infinite recursion detected in rules for relation \"%s\"",
01658 RelationGetRelationName(rel))));
01659 activeRIRs = lcons_oid(RelationGetRelid(rel), activeRIRs);
01660
01661 foreach(l, locks)
01662 {
01663 rule = lfirst(l);
01664
01665 parsetree = ApplyRetrieveRule(parsetree,
01666 rule,
01667 rt_index,
01668 rule->attrno == -1,
01669 rel,
01670 activeRIRs,
01671 forUpdatePushedDown);
01672 }
01673
01674 activeRIRs = list_delete_first(activeRIRs);
01675 }
01676
01677 heap_close(rel, NoLock);
01678 }
01679
01680
01681 foreach(lc, parsetree->cteList)
01682 {
01683 CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc);
01684
01685 cte->ctequery = (Node *)
01686 fireRIRrules((Query *) cte->ctequery, activeRIRs, false);
01687 }
01688
01689
01690
01691
01692
01693 if (parsetree->hasSubLinks)
01694 query_tree_walker(parsetree, fireRIRonSubLink, (void *) activeRIRs,
01695 QTW_IGNORE_RC_SUBQUERIES);
01696
01697 return parsetree;
01698 }
01699
01700
01701
01702
01703
01704
01705
01706
01707
01708
01709
01710
01711
01712
01713
01714 static Query *
01715 CopyAndAddInvertedQual(Query *parsetree,
01716 Node *rule_qual,
01717 int rt_index,
01718 CmdType event)
01719 {
01720
01721 Node *new_qual = (Node *) copyObject(rule_qual);
01722
01723
01724
01725
01726
01727
01728
01729 (void) acquireLocksOnSubLinks(new_qual, NULL);
01730
01731
01732 ChangeVarNodes(new_qual, PRS2_OLD_VARNO, rt_index, 0);
01733
01734 if (event == CMD_INSERT || event == CMD_UPDATE)
01735 new_qual = ReplaceVarsFromTargetList(new_qual,
01736 PRS2_NEW_VARNO,
01737 0,
01738 rt_fetch(rt_index,
01739 parsetree->rtable),
01740 parsetree->targetList,
01741 (event == CMD_UPDATE) ?
01742 REPLACEVARS_CHANGE_VARNO :
01743 REPLACEVARS_SUBSTITUTE_NULL,
01744 rt_index,
01745 &parsetree->hasSubLinks);
01746
01747 AddInvertedQual(parsetree, new_qual);
01748
01749 return parsetree;
01750 }
01751
01752
01753
01754
01755
01756
01757
01758
01759
01760
01761
01762
01763
01764
01765
01766
01767
01768
01769
01770
01771
01772
01773
01774
01775
01776
01777
01778
01779
01780
01781 static List *
01782 fireRules(Query *parsetree,
01783 int rt_index,
01784 CmdType event,
01785 List *locks,
01786 bool *instead_flag,
01787 bool *returning_flag,
01788 Query **qual_product)
01789 {
01790 List *results = NIL;
01791 ListCell *l;
01792
01793 foreach(l, locks)
01794 {
01795 RewriteRule *rule_lock = (RewriteRule *) lfirst(l);
01796 Node *event_qual = rule_lock->qual;
01797 List *actions = rule_lock->actions;
01798 QuerySource qsrc;
01799 ListCell *r;
01800
01801
01802 if (rule_lock->isInstead)
01803 {
01804 if (event_qual != NULL)
01805 qsrc = QSRC_QUAL_INSTEAD_RULE;
01806 else
01807 {
01808 qsrc = QSRC_INSTEAD_RULE;
01809 *instead_flag = true;
01810 }
01811 }
01812 else
01813 qsrc = QSRC_NON_INSTEAD_RULE;
01814
01815 if (qsrc == QSRC_QUAL_INSTEAD_RULE)
01816 {
01817
01818
01819
01820
01821
01822
01823
01824
01825
01826
01827
01828
01829 if (!*instead_flag)
01830 {
01831 if (*qual_product == NULL)
01832 *qual_product = copyObject(parsetree);
01833 *qual_product = CopyAndAddInvertedQual(*qual_product,
01834 event_qual,
01835 rt_index,
01836 event);
01837 }
01838 }
01839
01840
01841 foreach(r, actions)
01842 {
01843 Query *rule_action = lfirst(r);
01844
01845 if (rule_action->commandType == CMD_NOTHING)
01846 continue;
01847
01848 rule_action = rewriteRuleAction(parsetree, rule_action,
01849 event_qual, rt_index, event,
01850 returning_flag);
01851
01852 rule_action->querySource = qsrc;
01853 rule_action->canSetTag = false;
01854
01855 results = lappend(results, rule_action);
01856 }
01857 }
01858
01859 return results;
01860 }
01861
01862
01863
01864
01865
01866
01867
01868
01869 static Query *
01870 get_view_query(Relation view)
01871 {
01872 int i;
01873
01874 Assert(view->rd_rel->relkind == RELKIND_VIEW);
01875
01876 for (i = 0; i < view->rd_rules->numLocks; i++)
01877 {
01878 RewriteRule *rule = view->rd_rules->rules[i];
01879
01880 if (rule->event == CMD_SELECT)
01881 {
01882
01883 if (list_length(rule->actions) != 1)
01884 elog(ERROR, "invalid _RETURN rule action specification");
01885
01886 return (Query *) linitial(rule->actions);
01887 }
01888 }
01889
01890 elog(ERROR, "failed to find _RETURN rule for view");
01891 return NULL;
01892 }
01893
01894
01895
01896
01897
01898
01899
01900
01901 static bool
01902 view_has_instead_trigger(Relation view, CmdType event)
01903 {
01904 TriggerDesc *trigDesc = view->trigdesc;
01905
01906 switch (event)
01907 {
01908 case CMD_INSERT:
01909 if (trigDesc && trigDesc->trig_insert_instead_row)
01910 return true;
01911 break;
01912 case CMD_UPDATE:
01913 if (trigDesc && trigDesc->trig_update_instead_row)
01914 return true;
01915 break;
01916 case CMD_DELETE:
01917 if (trigDesc && trigDesc->trig_delete_instead_row)
01918 return true;
01919 break;
01920 default:
01921 elog(ERROR, "unrecognized CmdType: %d", (int) event);
01922 break;
01923 }
01924 return false;
01925 }
01926
01927
01928
01929
01930
01931
01932
01933
01934
01935
01936
01937
01938
01939
01940
01941
01942
01943 static const char *
01944 view_is_auto_updatable(Relation view)
01945 {
01946 Query *viewquery = get_view_query(view);
01947 RangeTblRef *rtr;
01948 RangeTblEntry *base_rte;
01949 Bitmapset *bms;
01950 ListCell *cell;
01951
01952
01953
01954
01955
01956
01957
01958
01959
01960
01961
01962
01963
01964
01965
01966
01967
01968
01969
01970
01971
01972
01973
01974
01975
01976
01977 if (viewquery->distinctClause != NIL)
01978 return gettext_noop("Views containing DISTINCT are not automatically updatable.");
01979
01980 if (viewquery->groupClause != NIL)
01981 return gettext_noop("Views containing GROUP BY are not automatically updatable.");
01982
01983 if (viewquery->havingQual != NULL)
01984 return gettext_noop("Views containing HAVING are not automatically updatable.");
01985
01986 if (viewquery->setOperations != NULL)
01987 return gettext_noop("Views containing UNION, INTERSECT, or EXCEPT are not automatically updatable.");
01988
01989 if (viewquery->cteList != NIL)
01990 return gettext_noop("Views containing WITH are not automatically updatable.");
01991
01992 if (viewquery->limitOffset != NULL || viewquery->limitCount != NULL)
01993 return gettext_noop("Views containing LIMIT or OFFSET are not automatically updatable.");
01994
01995
01996
01997
01998
01999
02000 if (RelationIsSecurityView(view))
02001 return gettext_noop("Security-barrier views are not automatically updatable.");
02002
02003
02004
02005
02006
02007 if (list_length(viewquery->jointree->fromlist) != 1)
02008 return gettext_noop("Views that do not select from a single table or view are not automatically updatable.");
02009
02010 rtr = (RangeTblRef *) linitial(viewquery->jointree->fromlist);
02011 if (!IsA(rtr, RangeTblRef))
02012 return gettext_noop("Views that do not select from a single table or view are not automatically updatable.");
02013
02014 base_rte = rt_fetch(rtr->rtindex, viewquery->rtable);
02015 if (base_rte->rtekind != RTE_RELATION ||
02016 (base_rte->relkind != RELKIND_RELATION &&
02017 base_rte->relkind != RELKIND_VIEW))
02018 return gettext_noop("Views that do not select from a single table or view are not automatically updatable.");
02019
02020
02021
02022
02023
02024
02025
02026
02027
02028
02029 bms = NULL;
02030 foreach(cell, viewquery->targetList)
02031 {
02032 TargetEntry *tle = (TargetEntry *) lfirst(cell);
02033 Var *var = (Var *) tle->expr;
02034
02035 if (tle->resjunk)
02036 continue;
02037
02038 if (!IsA(var, Var) ||
02039 var->varno != rtr->rtindex ||
02040 var->varlevelsup != 0)
02041 return gettext_noop("Views that return columns that are not columns of their base relation are not automatically updatable.");
02042
02043 if (var->varattno < 0)
02044 return gettext_noop("Views that return system columns are not automatically updatable.");
02045
02046 if (var->varattno == 0)
02047 return gettext_noop("Views that return whole-row references are not automatically updatable.");
02048
02049 if (bms_is_member(var->varattno, bms))
02050 return gettext_noop("Views that return the same column more than once are not automatically updatable.");
02051
02052 bms = bms_add_member(bms, var->varattno);
02053 }
02054 bms_free(bms);
02055
02056 return NULL;
02057 }
02058
02059
02060
02061
02062
02063
02064
02065
02066
02067
02068
02069
02070
02071
02072
02073
02074
02075
02076
02077
02078
02079
02080
02081
02082 bool
02083 relation_is_updatable(Oid reloid, int req_events)
02084 {
02085 Relation rel;
02086 RuleLock *rulelocks;
02087
02088 rel = try_relation_open(reloid, AccessShareLock);
02089
02090
02091
02092
02093
02094
02095
02096 if (rel == NULL)
02097 return false;
02098
02099
02100 rulelocks = rel->rd_rules;
02101 if (rulelocks != NULL)
02102 {
02103 int events = 0;
02104 int i;
02105
02106 for (i = 0; i < rulelocks->numLocks; i++)
02107 {
02108 if (rulelocks->rules[i]->isInstead &&
02109 rulelocks->rules[i]->qual == NULL)
02110 {
02111 events |= 1 << rulelocks->rules[i]->event;
02112 }
02113 }
02114
02115
02116 if ((events & req_events) == req_events)
02117 {
02118 relation_close(rel, AccessShareLock);
02119 return true;
02120 }
02121 }
02122
02123
02124 if (rel->rd_rel->relkind == RELKIND_VIEW &&
02125 view_is_auto_updatable(rel) == NULL)
02126 {
02127 Query *viewquery;
02128 RangeTblRef *rtr;
02129 RangeTblEntry *base_rte;
02130 Oid baseoid;
02131
02132
02133 viewquery = get_view_query(rel);
02134 rtr = (RangeTblRef *) linitial(viewquery->jointree->fromlist);
02135 base_rte = rt_fetch(rtr->rtindex, viewquery->rtable);
02136
02137 if (base_rte->relkind == RELKIND_RELATION)
02138 {
02139
02140 relation_close(rel, AccessShareLock);
02141 return true;
02142 }
02143 else
02144 {
02145
02146 baseoid = base_rte->relid;
02147 relation_close(rel, AccessShareLock);
02148 return relation_is_updatable(baseoid, req_events);
02149 }
02150 }
02151
02152
02153 relation_close(rel, AccessShareLock);
02154 return false;
02155 }
02156
02157
02158
02159
02160
02161
02162
02163
02164
02165
02166 static Bitmapset *
02167 adjust_view_column_set(Bitmapset *cols, List *targetlist)
02168 {
02169 Bitmapset *result = NULL;
02170 Bitmapset *tmpcols;
02171 AttrNumber col;
02172
02173 tmpcols = bms_copy(cols);
02174 while ((col = bms_first_member(tmpcols)) >= 0)
02175 {
02176
02177 AttrNumber attno = col + FirstLowInvalidHeapAttributeNumber;
02178
02179 if (attno == InvalidAttrNumber)
02180 {
02181
02182
02183
02184
02185
02186
02187
02188 ListCell *lc;
02189
02190 foreach(lc, targetlist)
02191 {
02192 TargetEntry *tle = (TargetEntry *) lfirst(lc);
02193 Var *var;
02194
02195 if (tle->resjunk)
02196 continue;
02197 var = (Var *) tle->expr;
02198 Assert(IsA(var, Var));
02199 result = bms_add_member(result,
02200 var->varattno - FirstLowInvalidHeapAttributeNumber);
02201 }
02202 }
02203 else
02204 {
02205
02206
02207
02208
02209
02210 TargetEntry *tle = get_tle_by_resno(targetlist, attno);
02211
02212 if (tle != NULL && !tle->resjunk && IsA(tle->expr, Var))
02213 {
02214 Var *var = (Var *) tle->expr;
02215
02216 result = bms_add_member(result,
02217 var->varattno - FirstLowInvalidHeapAttributeNumber);
02218 }
02219 else
02220 elog(ERROR, "attribute number %d not found in view targetlist",
02221 attno);
02222 }
02223 }
02224 bms_free(tmpcols);
02225
02226 return result;
02227 }
02228
02229
02230
02231
02232
02233
02234
02235
02236
02237
02238
02239 static Query *
02240 rewriteTargetView(Query *parsetree, Relation view)
02241 {
02242 const char *auto_update_detail;
02243 Query *viewquery;
02244 RangeTblRef *rtr;
02245 int base_rt_index;
02246 int new_rt_index;
02247 RangeTblEntry *base_rte;
02248 RangeTblEntry *view_rte;
02249 RangeTblEntry *new_rte;
02250 Relation base_rel;
02251 List *view_targetlist;
02252 ListCell *lc;
02253
02254
02255 auto_update_detail = view_is_auto_updatable(view);
02256 if (auto_update_detail)
02257 {
02258
02259 switch (parsetree->commandType)
02260 {
02261 case CMD_INSERT:
02262 ereport(ERROR,
02263 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
02264 errmsg("cannot insert into view \"%s\"",
02265 RelationGetRelationName(view)),
02266 errdetail_internal("%s", _(auto_update_detail)),
02267 errhint("To make the view insertable, provide an unconditional ON INSERT DO INSTEAD rule or an INSTEAD OF INSERT trigger.")));
02268 break;
02269 case CMD_UPDATE:
02270 ereport(ERROR,
02271 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
02272 errmsg("cannot update view \"%s\"",
02273 RelationGetRelationName(view)),
02274 errdetail_internal("%s", _(auto_update_detail)),
02275 errhint("To make the view updatable, provide an unconditional ON UPDATE DO INSTEAD rule or an INSTEAD OF UPDATE trigger.")));
02276 break;
02277 case CMD_DELETE:
02278 ereport(ERROR,
02279 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
02280 errmsg("cannot delete from view \"%s\"",
02281 RelationGetRelationName(view)),
02282 errdetail_internal("%s", _(auto_update_detail)),
02283 errhint("To make the view updatable, provide an unconditional ON DELETE DO INSTEAD rule or an INSTEAD OF DELETE trigger.")));
02284 break;
02285 default:
02286 elog(ERROR, "unrecognized CmdType: %d",
02287 (int) parsetree->commandType);
02288 break;
02289 }
02290 }
02291
02292
02293 view_rte = rt_fetch(parsetree->resultRelation, parsetree->rtable);
02294
02295
02296
02297
02298
02299 viewquery = get_view_query(view);
02300
02301 Assert(list_length(viewquery->jointree->fromlist) == 1);
02302 rtr = (RangeTblRef *) linitial(viewquery->jointree->fromlist);
02303 Assert(IsA(rtr, RangeTblRef));
02304
02305 base_rt_index = rtr->rtindex;
02306 base_rte = rt_fetch(base_rt_index, viewquery->rtable);
02307 Assert(base_rte->rtekind == RTE_RELATION);
02308
02309
02310
02311
02312
02313
02314
02315
02316 base_rel = heap_open(base_rte->relid, RowExclusiveLock);
02317
02318
02319
02320
02321
02322 base_rte->relkind = base_rel->rd_rel->relkind;
02323
02324 heap_close(base_rel, NoLock);
02325
02326
02327
02328
02329
02330
02331
02332
02333 new_rte = (RangeTblEntry *) copyObject(base_rte);
02334 parsetree->rtable = lappend(parsetree->rtable, new_rte);
02335 new_rt_index = list_length(parsetree->rtable);
02336
02337
02338
02339
02340
02341
02342
02343
02344
02345 view_targetlist = copyObject(viewquery->targetList);
02346
02347 ChangeVarNodes((Node *) view_targetlist,
02348 base_rt_index,
02349 new_rt_index,
02350 0);
02351
02352
02353
02354
02355
02356
02357
02358
02359
02360
02361
02362
02363
02364 new_rte->checkAsUser = view->rd_rel->relowner;
02365 new_rte->requiredPerms = view_rte->requiredPerms;
02366
02367
02368
02369
02370
02371
02372
02373
02374
02375
02376
02377
02378
02379
02380
02381
02382
02383
02384
02385
02386
02387
02388
02389
02390 Assert(bms_is_empty(new_rte->modifiedCols));
02391 new_rte->modifiedCols = adjust_view_column_set(view_rte->modifiedCols,
02392 view_targetlist);
02393
02394
02395
02396
02397
02398
02399
02400
02401
02402
02403 if (parsetree->commandType != CMD_INSERT)
02404 {
02405 TargetEntry *tle = (TargetEntry *) llast(parsetree->targetList);
02406
02407 Assert(tle->resjunk);
02408 Assert(IsA(tle->expr, Var) &&
02409 ((Var *) tle->expr)->varno == parsetree->resultRelation &&
02410 ((Var *) tle->expr)->varattno == 0);
02411 parsetree->targetList = list_delete_ptr(parsetree->targetList, tle);
02412 }
02413
02414
02415
02416
02417
02418 parsetree = (Query *)
02419 ReplaceVarsFromTargetList((Node *) parsetree,
02420 parsetree->resultRelation,
02421 0,
02422 view_rte,
02423 view_targetlist,
02424 REPLACEVARS_REPORT_ERROR,
02425 0,
02426 &parsetree->hasSubLinks);
02427
02428
02429
02430
02431
02432
02433
02434 ChangeVarNodes((Node *) parsetree,
02435 parsetree->resultRelation,
02436 new_rt_index,
02437 0);
02438 Assert(parsetree->resultRelation == new_rt_index);
02439
02440
02441
02442
02443
02444
02445
02446
02447
02448
02449 if (parsetree->commandType != CMD_DELETE)
02450 {
02451 foreach(lc, parsetree->targetList)
02452 {
02453 TargetEntry *tle = (TargetEntry *) lfirst(lc);
02454 TargetEntry *view_tle;
02455
02456 if (tle->resjunk)
02457 continue;
02458
02459 view_tle = get_tle_by_resno(view_targetlist, tle->resno);
02460 if (view_tle != NULL && !view_tle->resjunk && IsA(view_tle->expr, Var))
02461 tle->resno = ((Var *) view_tle->expr)->varattno;
02462 else
02463 elog(ERROR, "attribute number %d not found in view targetlist",
02464 tle->resno);
02465 }
02466 }
02467
02468
02469
02470
02471
02472
02473
02474
02475
02476
02477 if (parsetree->commandType != CMD_INSERT &&
02478 viewquery->jointree->quals != NULL)
02479 {
02480 Node *viewqual = (Node *) copyObject(viewquery->jointree->quals);
02481
02482 ChangeVarNodes(viewqual, base_rt_index, new_rt_index, 0);
02483 AddQual(parsetree, (Node *) viewqual);
02484 }
02485
02486 return parsetree;
02487 }
02488
02489
02490
02491
02492
02493
02494
02495
02496
02497 static List *
02498 RewriteQuery(Query *parsetree, List *rewrite_events)
02499 {
02500 CmdType event = parsetree->commandType;
02501 bool instead = false;
02502 bool returning = false;
02503 Query *qual_product = NULL;
02504 List *rewritten = NIL;
02505 ListCell *lc1;
02506
02507
02508
02509
02510
02511
02512 foreach(lc1, parsetree->cteList)
02513 {
02514 CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc1);
02515 Query *ctequery = (Query *) cte->ctequery;
02516 List *newstuff;
02517
02518 Assert(IsA(ctequery, Query));
02519
02520 if (ctequery->commandType == CMD_SELECT)
02521 continue;
02522
02523 newstuff = RewriteQuery(ctequery, rewrite_events);
02524
02525
02526
02527
02528
02529
02530 if (list_length(newstuff) == 1)
02531 {
02532
02533 ctequery = (Query *) linitial(newstuff);
02534 Assert(IsA(ctequery, Query));
02535
02536 Assert(!ctequery->canSetTag);
02537 cte->ctequery = (Node *) ctequery;
02538 }
02539 else if (newstuff == NIL)
02540 {
02541 ereport(ERROR,
02542 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
02543 errmsg("DO INSTEAD NOTHING rules are not supported for data-modifying statements in WITH")));
02544 }
02545 else
02546 {
02547 ListCell *lc2;
02548
02549
02550 foreach(lc2, newstuff)
02551 {
02552 Query *q = (Query *) lfirst(lc2);
02553
02554 if (q->querySource == QSRC_QUAL_INSTEAD_RULE)
02555 ereport(ERROR,
02556 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
02557 errmsg("conditional DO INSTEAD rules are not supported for data-modifying statements in WITH")));
02558 if (q->querySource == QSRC_NON_INSTEAD_RULE)
02559 ereport(ERROR,
02560 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
02561 errmsg("DO ALSO rules are not supported for data-modifying statements in WITH")));
02562 }
02563
02564 ereport(ERROR,
02565 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
02566 errmsg("multi-statement DO INSTEAD rules are not supported for data-modifying statements in WITH")));
02567 }
02568 }
02569
02570
02571
02572
02573
02574
02575
02576
02577
02578 if (event != CMD_SELECT && event != CMD_UTILITY)
02579 {
02580 int result_relation;
02581 RangeTblEntry *rt_entry;
02582 Relation rt_entry_relation;
02583 List *locks;
02584 List *product_queries;
02585
02586 result_relation = parsetree->resultRelation;
02587 Assert(result_relation != 0);
02588 rt_entry = rt_fetch(result_relation, parsetree->rtable);
02589 Assert(rt_entry->rtekind == RTE_RELATION);
02590
02591
02592
02593
02594
02595 rt_entry_relation = heap_open(rt_entry->relid, NoLock);
02596
02597
02598
02599
02600 if (event == CMD_INSERT)
02601 {
02602 RangeTblEntry *values_rte = NULL;
02603
02604
02605
02606
02607
02608 if (list_length(parsetree->jointree->fromlist) == 1)
02609 {
02610 RangeTblRef *rtr = (RangeTblRef *) linitial(parsetree->jointree->fromlist);
02611
02612 if (IsA(rtr, RangeTblRef))
02613 {
02614 RangeTblEntry *rte = rt_fetch(rtr->rtindex,
02615 parsetree->rtable);
02616
02617 if (rte->rtekind == RTE_VALUES)
02618 values_rte = rte;
02619 }
02620 }
02621
02622 if (values_rte)
02623 {
02624 List *attrnos;
02625
02626
02627 rewriteTargetListIU(parsetree, rt_entry_relation, &attrnos);
02628
02629 rewriteValuesRTE(values_rte, rt_entry_relation, attrnos);
02630 }
02631 else
02632 {
02633
02634 rewriteTargetListIU(parsetree, rt_entry_relation, NULL);
02635 }
02636 }
02637 else if (event == CMD_UPDATE)
02638 {
02639 rewriteTargetListIU(parsetree, rt_entry_relation, NULL);
02640 rewriteTargetListUD(parsetree, rt_entry, rt_entry_relation);
02641 }
02642 else if (event == CMD_DELETE)
02643 {
02644 rewriteTargetListUD(parsetree, rt_entry, rt_entry_relation);
02645 }
02646 else
02647 elog(ERROR, "unrecognized commandType: %d", (int) event);
02648
02649
02650
02651
02652 locks = matchLocks(event, rt_entry_relation->rd_rules,
02653 result_relation, parsetree);
02654
02655 product_queries = fireRules(parsetree,
02656 result_relation,
02657 event,
02658 locks,
02659 &instead,
02660 &returning,
02661 &qual_product);
02662
02663
02664
02665
02666
02667
02668
02669
02670
02671 if (!instead && qual_product == NULL &&
02672 rt_entry_relation->rd_rel->relkind == RELKIND_VIEW &&
02673 !view_has_instead_trigger(rt_entry_relation, event))
02674 {
02675
02676
02677
02678
02679
02680 parsetree = rewriteTargetView(parsetree, rt_entry_relation);
02681
02682
02683
02684
02685
02686
02687
02688 if (parsetree->commandType == CMD_INSERT)
02689 product_queries = lcons(parsetree, product_queries);
02690 else
02691 product_queries = lappend(product_queries, parsetree);
02692
02693
02694
02695
02696
02697
02698
02699
02700 instead = true;
02701 returning = true;
02702 }
02703
02704
02705
02706
02707
02708 if (product_queries != NIL)
02709 {
02710 ListCell *n;
02711 rewrite_event *rev;
02712
02713 foreach(n, rewrite_events)
02714 {
02715 rev = (rewrite_event *) lfirst(n);
02716 if (rev->relation == RelationGetRelid(rt_entry_relation) &&
02717 rev->event == event)
02718 ereport(ERROR,
02719 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
02720 errmsg("infinite recursion detected in rules for relation \"%s\"",
02721 RelationGetRelationName(rt_entry_relation))));
02722 }
02723
02724 rev = (rewrite_event *) palloc(sizeof(rewrite_event));
02725 rev->relation = RelationGetRelid(rt_entry_relation);
02726 rev->event = event;
02727 rewrite_events = lcons(rev, rewrite_events);
02728
02729 foreach(n, product_queries)
02730 {
02731 Query *pt = (Query *) lfirst(n);
02732 List *newstuff;
02733
02734 newstuff = RewriteQuery(pt, rewrite_events);
02735 rewritten = list_concat(rewritten, newstuff);
02736 }
02737
02738 rewrite_events = list_delete_first(rewrite_events);
02739 }
02740
02741
02742
02743
02744
02745
02746
02747
02748 if ((instead || qual_product != NULL) &&
02749 parsetree->returningList &&
02750 !returning)
02751 {
02752 switch (event)
02753 {
02754 case CMD_INSERT:
02755 ereport(ERROR,
02756 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
02757 errmsg("cannot perform INSERT RETURNING on relation \"%s\"",
02758 RelationGetRelationName(rt_entry_relation)),
02759 errhint("You need an unconditional ON INSERT DO INSTEAD rule with a RETURNING clause.")));
02760 break;
02761 case CMD_UPDATE:
02762 ereport(ERROR,
02763 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
02764 errmsg("cannot perform UPDATE RETURNING on relation \"%s\"",
02765 RelationGetRelationName(rt_entry_relation)),
02766 errhint("You need an unconditional ON UPDATE DO INSTEAD rule with a RETURNING clause.")));
02767 break;
02768 case CMD_DELETE:
02769 ereport(ERROR,
02770 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
02771 errmsg("cannot perform DELETE RETURNING on relation \"%s\"",
02772 RelationGetRelationName(rt_entry_relation)),
02773 errhint("You need an unconditional ON DELETE DO INSTEAD rule with a RETURNING clause.")));
02774 break;
02775 default:
02776 elog(ERROR, "unrecognized commandType: %d",
02777 (int) event);
02778 break;
02779 }
02780 }
02781
02782 heap_close(rt_entry_relation, NoLock);
02783 }
02784
02785
02786
02787
02788
02789
02790
02791
02792
02793
02794
02795
02796
02797 if (!instead)
02798 {
02799 if (parsetree->commandType == CMD_INSERT)
02800 {
02801 if (qual_product != NULL)
02802 rewritten = lcons(qual_product, rewritten);
02803 else
02804 rewritten = lcons(parsetree, rewritten);
02805 }
02806 else
02807 {
02808 if (qual_product != NULL)
02809 rewritten = lappend(rewritten, qual_product);
02810 else
02811 rewritten = lappend(rewritten, parsetree);
02812 }
02813 }
02814
02815
02816
02817
02818
02819
02820
02821
02822
02823 if (parsetree->cteList != NIL)
02824 {
02825 int qcount = 0;
02826
02827 foreach(lc1, rewritten)
02828 {
02829 Query *q = (Query *) lfirst(lc1);
02830
02831 if (q->commandType != CMD_UTILITY)
02832 qcount++;
02833 }
02834 if (qcount > 1)
02835 ereport(ERROR,
02836 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
02837 errmsg("WITH cannot be used in a query that is rewritten by rules into multiple queries")));
02838 }
02839
02840 return rewritten;
02841 }
02842
02843
02844
02845
02846
02847
02848
02849
02850
02851
02852
02853 List *
02854 QueryRewrite(Query *parsetree)
02855 {
02856 uint32 input_query_id = parsetree->queryId;
02857 List *querylist;
02858 List *results;
02859 ListCell *l;
02860 CmdType origCmdType;
02861 bool foundOriginalQuery;
02862 Query *lastInstead;
02863
02864
02865
02866
02867 Assert(parsetree->querySource == QSRC_ORIGINAL);
02868 Assert(parsetree->canSetTag);
02869
02870
02871
02872
02873
02874
02875 querylist = RewriteQuery(parsetree, NIL);
02876
02877
02878
02879
02880
02881
02882
02883
02884 results = NIL;
02885 foreach(l, querylist)
02886 {
02887 Query *query = (Query *) lfirst(l);
02888
02889 query = fireRIRrules(query, NIL, false);
02890
02891 query->queryId = input_query_id;
02892
02893 results = lappend(results, query);
02894 }
02895
02896
02897
02898
02899
02900
02901
02902
02903
02904
02905
02906
02907
02908
02909
02910
02911
02912 origCmdType = parsetree->commandType;
02913 foundOriginalQuery = false;
02914 lastInstead = NULL;
02915
02916 foreach(l, results)
02917 {
02918 Query *query = (Query *) lfirst(l);
02919
02920 if (query->querySource == QSRC_ORIGINAL)
02921 {
02922 Assert(query->canSetTag);
02923 Assert(!foundOriginalQuery);
02924 foundOriginalQuery = true;
02925 #ifndef USE_ASSERT_CHECKING
02926 break;
02927 #endif
02928 }
02929 else
02930 {
02931 Assert(!query->canSetTag);
02932 if (query->commandType == origCmdType &&
02933 (query->querySource == QSRC_INSTEAD_RULE ||
02934 query->querySource == QSRC_QUAL_INSTEAD_RULE))
02935 lastInstead = query;
02936 }
02937 }
02938
02939 if (!foundOriginalQuery && lastInstead != NULL)
02940 lastInstead->canSetTag = true;
02941
02942 return results;
02943 }