00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033 #include "postgres.h"
00034
00035 #include "postgres_fdw.h"
00036
00037 #include "access/heapam.h"
00038 #include "access/htup_details.h"
00039 #include "access/sysattr.h"
00040 #include "access/transam.h"
00041 #include "catalog/pg_collation.h"
00042 #include "catalog/pg_namespace.h"
00043 #include "catalog/pg_operator.h"
00044 #include "catalog/pg_proc.h"
00045 #include "catalog/pg_type.h"
00046 #include "commands/defrem.h"
00047 #include "nodes/nodeFuncs.h"
00048 #include "optimizer/clauses.h"
00049 #include "optimizer/var.h"
00050 #include "parser/parsetree.h"
00051 #include "utils/builtins.h"
00052 #include "utils/lsyscache.h"
00053 #include "utils/syscache.h"
00054
00055
00056
00057
00058
00059 typedef struct foreign_glob_cxt
00060 {
00061 PlannerInfo *root;
00062 RelOptInfo *foreignrel;
00063 } foreign_glob_cxt;
00064
00065
00066
00067
00068
00069 typedef enum
00070 {
00071 FDW_COLLATE_NONE,
00072 FDW_COLLATE_SAFE,
00073 FDW_COLLATE_UNSAFE
00074 } FDWCollateState;
00075
00076 typedef struct foreign_loc_cxt
00077 {
00078 Oid collation;
00079 FDWCollateState state;
00080 } foreign_loc_cxt;
00081
00082
00083
00084
00085 typedef struct deparse_expr_cxt
00086 {
00087 PlannerInfo *root;
00088 RelOptInfo *foreignrel;
00089 StringInfo buf;
00090 List **params_list;
00091 } deparse_expr_cxt;
00092
00093
00094
00095
00096
00097 static bool foreign_expr_walker(Node *node,
00098 foreign_glob_cxt *glob_cxt,
00099 foreign_loc_cxt *outer_cxt);
00100 static bool is_builtin(Oid procid);
00101
00102
00103
00104
00105 static void deparseTargetList(StringInfo buf,
00106 PlannerInfo *root,
00107 Index rtindex,
00108 Relation rel,
00109 Bitmapset *attrs_used,
00110 List **retrieved_attrs);
00111 static void deparseReturningList(StringInfo buf, PlannerInfo *root,
00112 Index rtindex, Relation rel,
00113 List *returningList,
00114 List **retrieved_attrs);
00115 static void deparseColumnRef(StringInfo buf, int varno, int varattno,
00116 PlannerInfo *root);
00117 static void deparseRelation(StringInfo buf, Relation rel);
00118 static void deparseStringLiteral(StringInfo buf, const char *val);
00119 static void deparseExpr(Expr *expr, deparse_expr_cxt *context);
00120 static void deparseVar(Var *node, deparse_expr_cxt *context);
00121 static void deparseConst(Const *node, deparse_expr_cxt *context);
00122 static void deparseParam(Param *node, deparse_expr_cxt *context);
00123 static void deparseArrayRef(ArrayRef *node, deparse_expr_cxt *context);
00124 static void deparseFuncExpr(FuncExpr *node, deparse_expr_cxt *context);
00125 static void deparseOpExpr(OpExpr *node, deparse_expr_cxt *context);
00126 static void deparseOperatorName(StringInfo buf, Form_pg_operator opform);
00127 static void deparseDistinctExpr(DistinctExpr *node, deparse_expr_cxt *context);
00128 static void deparseScalarArrayOpExpr(ScalarArrayOpExpr *node,
00129 deparse_expr_cxt *context);
00130 static void deparseRelabelType(RelabelType *node, deparse_expr_cxt *context);
00131 static void deparseBoolExpr(BoolExpr *node, deparse_expr_cxt *context);
00132 static void deparseNullTest(NullTest *node, deparse_expr_cxt *context);
00133 static void deparseArrayExpr(ArrayExpr *node, deparse_expr_cxt *context);
00134
00135
00136
00137
00138
00139
00140
00141
00142 void
00143 classifyConditions(PlannerInfo *root,
00144 RelOptInfo *baserel,
00145 List **remote_conds,
00146 List **local_conds)
00147 {
00148 ListCell *lc;
00149
00150 *remote_conds = NIL;
00151 *local_conds = NIL;
00152
00153 foreach(lc, baserel->baserestrictinfo)
00154 {
00155 RestrictInfo *ri = (RestrictInfo *) lfirst(lc);
00156
00157 if (is_foreign_expr(root, baserel, ri->clause))
00158 *remote_conds = lappend(*remote_conds, ri);
00159 else
00160 *local_conds = lappend(*local_conds, ri);
00161 }
00162 }
00163
00164
00165
00166
00167 bool
00168 is_foreign_expr(PlannerInfo *root,
00169 RelOptInfo *baserel,
00170 Expr *expr)
00171 {
00172 foreign_glob_cxt glob_cxt;
00173 foreign_loc_cxt loc_cxt;
00174
00175
00176
00177
00178
00179 glob_cxt.root = root;
00180 glob_cxt.foreignrel = baserel;
00181 loc_cxt.collation = InvalidOid;
00182 loc_cxt.state = FDW_COLLATE_NONE;
00183 if (!foreign_expr_walker((Node *) expr, &glob_cxt, &loc_cxt))
00184 return false;
00185
00186
00187 Assert(loc_cxt.collation == InvalidOid);
00188 Assert(loc_cxt.state == FDW_COLLATE_NONE);
00189
00190
00191
00192
00193
00194
00195
00196
00197 if (contain_mutable_functions((Node *) expr))
00198 return false;
00199
00200
00201 return true;
00202 }
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216 static bool
00217 foreign_expr_walker(Node *node,
00218 foreign_glob_cxt *glob_cxt,
00219 foreign_loc_cxt *outer_cxt)
00220 {
00221 bool check_type = true;
00222 foreign_loc_cxt inner_cxt;
00223 Oid collation;
00224 FDWCollateState state;
00225
00226
00227 if (node == NULL)
00228 return true;
00229
00230
00231 inner_cxt.collation = InvalidOid;
00232 inner_cxt.state = FDW_COLLATE_NONE;
00233
00234 switch (nodeTag(node))
00235 {
00236 case T_Var:
00237 {
00238 Var *var = (Var *) node;
00239
00240
00241
00242
00243
00244
00245
00246
00247 if (var->varno == glob_cxt->foreignrel->relid &&
00248 var->varlevelsup == 0)
00249 {
00250
00251 collation = var->varcollid;
00252 state = OidIsValid(collation) ? FDW_COLLATE_SAFE : FDW_COLLATE_NONE;
00253 }
00254 else
00255 {
00256
00257 if (var->varcollid != InvalidOid &&
00258 var->varcollid != DEFAULT_COLLATION_OID)
00259 return false;
00260
00261
00262 collation = InvalidOid;
00263 state = FDW_COLLATE_NONE;
00264 }
00265 }
00266 break;
00267 case T_Const:
00268 {
00269 Const *c = (Const *) node;
00270
00271
00272
00273
00274
00275
00276 if (c->constcollid != InvalidOid &&
00277 c->constcollid != DEFAULT_COLLATION_OID)
00278 return false;
00279
00280
00281 collation = InvalidOid;
00282 state = FDW_COLLATE_NONE;
00283 }
00284 break;
00285 case T_Param:
00286 {
00287 Param *p = (Param *) node;
00288
00289
00290
00291
00292 if (p->paramcollid != InvalidOid &&
00293 p->paramcollid != DEFAULT_COLLATION_OID)
00294 return false;
00295
00296 collation = InvalidOid;
00297 state = FDW_COLLATE_NONE;
00298 }
00299 break;
00300 case T_ArrayRef:
00301 {
00302 ArrayRef *ar = (ArrayRef *) node;;
00303
00304
00305 if (ar->refassgnexpr != NULL)
00306 return false;
00307
00308
00309
00310
00311
00312
00313 if (!foreign_expr_walker((Node *) ar->refupperindexpr,
00314 glob_cxt, &inner_cxt))
00315 return false;
00316 if (!foreign_expr_walker((Node *) ar->reflowerindexpr,
00317 glob_cxt, &inner_cxt))
00318 return false;
00319 if (!foreign_expr_walker((Node *) ar->refexpr,
00320 glob_cxt, &inner_cxt))
00321 return false;
00322
00323
00324
00325
00326
00327 collation = ar->refcollid;
00328 if (collation == InvalidOid)
00329 state = FDW_COLLATE_NONE;
00330 else if (inner_cxt.state == FDW_COLLATE_SAFE &&
00331 collation == inner_cxt.collation)
00332 state = FDW_COLLATE_SAFE;
00333 else
00334 state = FDW_COLLATE_UNSAFE;
00335 }
00336 break;
00337 case T_FuncExpr:
00338 {
00339 FuncExpr *fe = (FuncExpr *) node;
00340
00341
00342
00343
00344
00345
00346 if (!is_builtin(fe->funcid))
00347 return false;
00348
00349
00350
00351
00352 if (!foreign_expr_walker((Node *) fe->args,
00353 glob_cxt, &inner_cxt))
00354 return false;
00355
00356
00357
00358
00359
00360 if (fe->inputcollid == InvalidOid)
00361 ;
00362 else if (inner_cxt.state != FDW_COLLATE_SAFE ||
00363 fe->inputcollid != inner_cxt.collation)
00364 return false;
00365
00366
00367
00368
00369
00370
00371
00372 collation = fe->funccollid;
00373 if (collation == InvalidOid)
00374 state = FDW_COLLATE_NONE;
00375 else if (inner_cxt.state == FDW_COLLATE_SAFE &&
00376 collation == inner_cxt.collation)
00377 state = FDW_COLLATE_SAFE;
00378 else
00379 state = FDW_COLLATE_UNSAFE;
00380 }
00381 break;
00382 case T_OpExpr:
00383 case T_DistinctExpr:
00384 {
00385 OpExpr *oe = (OpExpr *) node;
00386
00387
00388
00389
00390
00391
00392 if (!is_builtin(oe->opno))
00393 return false;
00394
00395
00396
00397
00398 if (!foreign_expr_walker((Node *) oe->args,
00399 glob_cxt, &inner_cxt))
00400 return false;
00401
00402
00403
00404
00405
00406 if (oe->inputcollid == InvalidOid)
00407 ;
00408 else if (inner_cxt.state != FDW_COLLATE_SAFE ||
00409 oe->inputcollid != inner_cxt.collation)
00410 return false;
00411
00412
00413 collation = oe->opcollid;
00414 if (collation == InvalidOid)
00415 state = FDW_COLLATE_NONE;
00416 else if (inner_cxt.state == FDW_COLLATE_SAFE &&
00417 collation == inner_cxt.collation)
00418 state = FDW_COLLATE_SAFE;
00419 else
00420 state = FDW_COLLATE_UNSAFE;
00421 }
00422 break;
00423 case T_ScalarArrayOpExpr:
00424 {
00425 ScalarArrayOpExpr *oe = (ScalarArrayOpExpr *) node;
00426
00427
00428
00429
00430 if (!is_builtin(oe->opno))
00431 return false;
00432
00433
00434
00435
00436 if (!foreign_expr_walker((Node *) oe->args,
00437 glob_cxt, &inner_cxt))
00438 return false;
00439
00440
00441
00442
00443
00444 if (oe->inputcollid == InvalidOid)
00445 ;
00446 else if (inner_cxt.state != FDW_COLLATE_SAFE ||
00447 oe->inputcollid != inner_cxt.collation)
00448 return false;
00449
00450
00451 collation = InvalidOid;
00452 state = FDW_COLLATE_NONE;
00453 }
00454 break;
00455 case T_RelabelType:
00456 {
00457 RelabelType *r = (RelabelType *) node;
00458
00459
00460
00461
00462 if (!foreign_expr_walker((Node *) r->arg,
00463 glob_cxt, &inner_cxt))
00464 return false;
00465
00466
00467
00468
00469
00470 collation = r->resultcollid;
00471 if (collation == InvalidOid)
00472 state = FDW_COLLATE_NONE;
00473 else if (inner_cxt.state == FDW_COLLATE_SAFE &&
00474 collation == inner_cxt.collation)
00475 state = FDW_COLLATE_SAFE;
00476 else
00477 state = FDW_COLLATE_UNSAFE;
00478 }
00479 break;
00480 case T_BoolExpr:
00481 {
00482 BoolExpr *b = (BoolExpr *) node;
00483
00484
00485
00486
00487 if (!foreign_expr_walker((Node *) b->args,
00488 glob_cxt, &inner_cxt))
00489 return false;
00490
00491
00492 collation = InvalidOid;
00493 state = FDW_COLLATE_NONE;
00494 }
00495 break;
00496 case T_NullTest:
00497 {
00498 NullTest *nt = (NullTest *) node;
00499
00500
00501
00502
00503 if (!foreign_expr_walker((Node *) nt->arg,
00504 glob_cxt, &inner_cxt))
00505 return false;
00506
00507
00508 collation = InvalidOid;
00509 state = FDW_COLLATE_NONE;
00510 }
00511 break;
00512 case T_ArrayExpr:
00513 {
00514 ArrayExpr *a = (ArrayExpr *) node;
00515
00516
00517
00518
00519 if (!foreign_expr_walker((Node *) a->elements,
00520 glob_cxt, &inner_cxt))
00521 return false;
00522
00523
00524
00525
00526
00527 collation = a->array_collid;
00528 if (collation == InvalidOid)
00529 state = FDW_COLLATE_NONE;
00530 else if (inner_cxt.state == FDW_COLLATE_SAFE &&
00531 collation == inner_cxt.collation)
00532 state = FDW_COLLATE_SAFE;
00533 else
00534 state = FDW_COLLATE_UNSAFE;
00535 }
00536 break;
00537 case T_List:
00538 {
00539 List *l = (List *) node;
00540 ListCell *lc;
00541
00542
00543
00544
00545 foreach(lc, l)
00546 {
00547 if (!foreign_expr_walker((Node *) lfirst(lc),
00548 glob_cxt, &inner_cxt))
00549 return false;
00550 }
00551
00552
00553
00554
00555
00556 collation = inner_cxt.collation;
00557 state = inner_cxt.state;
00558
00559
00560 check_type = false;
00561 }
00562 break;
00563 default:
00564
00565
00566
00567
00568
00569 return false;
00570 }
00571
00572
00573
00574
00575
00576 if (check_type && !is_builtin(exprType(node)))
00577 return false;
00578
00579
00580
00581
00582 if (state > outer_cxt->state)
00583 {
00584
00585 outer_cxt->collation = collation;
00586 outer_cxt->state = state;
00587 }
00588 else if (state == outer_cxt->state)
00589 {
00590
00591 switch (state)
00592 {
00593 case FDW_COLLATE_NONE:
00594
00595 break;
00596 case FDW_COLLATE_SAFE:
00597 if (collation != outer_cxt->collation)
00598 {
00599
00600
00601
00602 if (outer_cxt->collation == DEFAULT_COLLATION_OID)
00603 {
00604
00605 outer_cxt->collation = collation;
00606 }
00607 else if (collation != DEFAULT_COLLATION_OID)
00608 {
00609
00610
00611
00612
00613
00614 outer_cxt->state = FDW_COLLATE_UNSAFE;
00615 }
00616 }
00617 break;
00618 case FDW_COLLATE_UNSAFE:
00619
00620 break;
00621 }
00622 }
00623
00624
00625 return true;
00626 }
00627
00628
00629
00630
00631
00632
00633
00634
00635
00636
00637
00638
00639
00640
00641
00642
00643
00644
00645
00646 static bool
00647 is_builtin(Oid oid)
00648 {
00649 return (oid < FirstBootstrapObjectId);
00650 }
00651
00652
00653
00654
00655
00656
00657
00658
00659
00660
00661 void
00662 deparseSelectSql(StringInfo buf,
00663 PlannerInfo *root,
00664 RelOptInfo *baserel,
00665 Bitmapset *attrs_used,
00666 List **retrieved_attrs)
00667 {
00668 RangeTblEntry *rte = planner_rt_fetch(baserel->relid, root);
00669 Relation rel;
00670
00671
00672
00673
00674
00675 rel = heap_open(rte->relid, NoLock);
00676
00677
00678
00679
00680 appendStringInfoString(buf, "SELECT ");
00681 deparseTargetList(buf, root, baserel->relid, rel, attrs_used,
00682 retrieved_attrs);
00683
00684
00685
00686
00687 appendStringInfoString(buf, " FROM ");
00688 deparseRelation(buf, rel);
00689
00690 heap_close(rel, NoLock);
00691 }
00692
00693
00694
00695
00696
00697
00698
00699
00700 static void
00701 deparseTargetList(StringInfo buf,
00702 PlannerInfo *root,
00703 Index rtindex,
00704 Relation rel,
00705 Bitmapset *attrs_used,
00706 List **retrieved_attrs)
00707 {
00708 TupleDesc tupdesc = RelationGetDescr(rel);
00709 bool have_wholerow;
00710 bool first;
00711 int i;
00712
00713 *retrieved_attrs = NIL;
00714
00715
00716 have_wholerow = bms_is_member(0 - FirstLowInvalidHeapAttributeNumber,
00717 attrs_used);
00718
00719 first = true;
00720 for (i = 1; i <= tupdesc->natts; i++)
00721 {
00722 Form_pg_attribute attr = tupdesc->attrs[i - 1];
00723
00724
00725 if (attr->attisdropped)
00726 continue;
00727
00728 if (have_wholerow ||
00729 bms_is_member(i - FirstLowInvalidHeapAttributeNumber,
00730 attrs_used))
00731 {
00732 if (!first)
00733 appendStringInfoString(buf, ", ");
00734 first = false;
00735
00736 deparseColumnRef(buf, rtindex, i, root);
00737
00738 *retrieved_attrs = lappend_int(*retrieved_attrs, i);
00739 }
00740 }
00741
00742
00743
00744
00745
00746 if (bms_is_member(SelfItemPointerAttributeNumber - FirstLowInvalidHeapAttributeNumber,
00747 attrs_used))
00748 {
00749 if (!first)
00750 appendStringInfoString(buf, ", ");
00751 first = false;
00752
00753 appendStringInfoString(buf, "ctid");
00754
00755 *retrieved_attrs = lappend_int(*retrieved_attrs,
00756 SelfItemPointerAttributeNumber);
00757 }
00758
00759
00760 if (first)
00761 appendStringInfoString(buf, "NULL");
00762 }
00763
00764
00765
00766
00767
00768
00769
00770
00771
00772
00773
00774
00775
00776
00777
00778 void
00779 appendWhereClause(StringInfo buf,
00780 PlannerInfo *root,
00781 RelOptInfo *baserel,
00782 List *exprs,
00783 bool is_first,
00784 List **params)
00785 {
00786 deparse_expr_cxt context;
00787 int nestlevel;
00788 ListCell *lc;
00789
00790 if (params)
00791 *params = NIL;
00792
00793
00794 context.root = root;
00795 context.foreignrel = baserel;
00796 context.buf = buf;
00797 context.params_list = params;
00798
00799
00800 nestlevel = set_transmission_modes();
00801
00802 foreach(lc, exprs)
00803 {
00804 RestrictInfo *ri = (RestrictInfo *) lfirst(lc);
00805
00806
00807 if (is_first)
00808 appendStringInfoString(buf, " WHERE ");
00809 else
00810 appendStringInfoString(buf, " AND ");
00811
00812 appendStringInfoChar(buf, '(');
00813 deparseExpr(ri->clause, &context);
00814 appendStringInfoChar(buf, ')');
00815
00816 is_first = false;
00817 }
00818
00819 reset_transmission_modes(nestlevel);
00820 }
00821
00822
00823
00824
00825
00826
00827
00828
00829 void
00830 deparseInsertSql(StringInfo buf, PlannerInfo *root,
00831 Index rtindex, Relation rel,
00832 List *targetAttrs, List *returningList,
00833 List **retrieved_attrs)
00834 {
00835 AttrNumber pindex;
00836 bool first;
00837 ListCell *lc;
00838
00839 appendStringInfoString(buf, "INSERT INTO ");
00840 deparseRelation(buf, rel);
00841
00842 if (targetAttrs)
00843 {
00844 appendStringInfoString(buf, "(");
00845
00846 first = true;
00847 foreach(lc, targetAttrs)
00848 {
00849 int attnum = lfirst_int(lc);
00850
00851 if (!first)
00852 appendStringInfoString(buf, ", ");
00853 first = false;
00854
00855 deparseColumnRef(buf, rtindex, attnum, root);
00856 }
00857
00858 appendStringInfoString(buf, ") VALUES (");
00859
00860 pindex = 1;
00861 first = true;
00862 foreach(lc, targetAttrs)
00863 {
00864 if (!first)
00865 appendStringInfoString(buf, ", ");
00866 first = false;
00867
00868 appendStringInfo(buf, "$%d", pindex);
00869 pindex++;
00870 }
00871
00872 appendStringInfoString(buf, ")");
00873 }
00874 else
00875 appendStringInfoString(buf, " DEFAULT VALUES");
00876
00877 if (returningList)
00878 deparseReturningList(buf, root, rtindex, rel, returningList,
00879 retrieved_attrs);
00880 else
00881 *retrieved_attrs = NIL;
00882 }
00883
00884
00885
00886
00887
00888
00889
00890
00891 void
00892 deparseUpdateSql(StringInfo buf, PlannerInfo *root,
00893 Index rtindex, Relation rel,
00894 List *targetAttrs, List *returningList,
00895 List **retrieved_attrs)
00896 {
00897 AttrNumber pindex;
00898 bool first;
00899 ListCell *lc;
00900
00901 appendStringInfoString(buf, "UPDATE ");
00902 deparseRelation(buf, rel);
00903 appendStringInfoString(buf, " SET ");
00904
00905 pindex = 2;
00906 first = true;
00907 foreach(lc, targetAttrs)
00908 {
00909 int attnum = lfirst_int(lc);
00910
00911 if (!first)
00912 appendStringInfoString(buf, ", ");
00913 first = false;
00914
00915 deparseColumnRef(buf, rtindex, attnum, root);
00916 appendStringInfo(buf, " = $%d", pindex);
00917 pindex++;
00918 }
00919 appendStringInfoString(buf, " WHERE ctid = $1");
00920
00921 if (returningList)
00922 deparseReturningList(buf, root, rtindex, rel, returningList,
00923 retrieved_attrs);
00924 else
00925 *retrieved_attrs = NIL;
00926 }
00927
00928
00929
00930
00931
00932
00933
00934
00935 void
00936 deparseDeleteSql(StringInfo buf, PlannerInfo *root,
00937 Index rtindex, Relation rel,
00938 List *returningList,
00939 List **retrieved_attrs)
00940 {
00941 appendStringInfoString(buf, "DELETE FROM ");
00942 deparseRelation(buf, rel);
00943 appendStringInfoString(buf, " WHERE ctid = $1");
00944
00945 if (returningList)
00946 deparseReturningList(buf, root, rtindex, rel, returningList,
00947 retrieved_attrs);
00948 else
00949 *retrieved_attrs = NIL;
00950 }
00951
00952
00953
00954
00955 static void
00956 deparseReturningList(StringInfo buf, PlannerInfo *root,
00957 Index rtindex, Relation rel,
00958 List *returningList,
00959 List **retrieved_attrs)
00960 {
00961 Bitmapset *attrs_used;
00962
00963
00964
00965
00966 attrs_used = NULL;
00967 pull_varattnos((Node *) returningList, rtindex,
00968 &attrs_used);
00969
00970 appendStringInfoString(buf, " RETURNING ");
00971 deparseTargetList(buf, root, rtindex, rel, attrs_used,
00972 retrieved_attrs);
00973 }
00974
00975
00976
00977
00978
00979
00980
00981
00982
00983 void
00984 deparseAnalyzeSizeSql(StringInfo buf, Relation rel)
00985 {
00986 StringInfoData relname;
00987
00988
00989 initStringInfo(&relname);
00990 deparseRelation(&relname, rel);
00991
00992 appendStringInfo(buf, "SELECT pg_catalog.pg_relation_size(");
00993 deparseStringLiteral(buf, relname.data);
00994 appendStringInfo(buf, "::pg_catalog.regclass) / %d", BLCKSZ);
00995 }
00996
00997
00998
00999
01000
01001
01002
01003 void
01004 deparseAnalyzeSql(StringInfo buf, Relation rel, List **retrieved_attrs)
01005 {
01006 Oid relid = RelationGetRelid(rel);
01007 TupleDesc tupdesc = RelationGetDescr(rel);
01008 int i;
01009 char *colname;
01010 List *options;
01011 ListCell *lc;
01012 bool first = true;
01013
01014 *retrieved_attrs = NIL;
01015
01016 appendStringInfoString(buf, "SELECT ");
01017 for (i = 0; i < tupdesc->natts; i++)
01018 {
01019
01020 if (tupdesc->attrs[i]->attisdropped)
01021 continue;
01022
01023 if (!first)
01024 appendStringInfoString(buf, ", ");
01025 first = false;
01026
01027
01028 colname = NameStr(tupdesc->attrs[i]->attname);
01029 options = GetForeignColumnOptions(relid, i + 1);
01030
01031 foreach(lc, options)
01032 {
01033 DefElem *def = (DefElem *) lfirst(lc);
01034
01035 if (strcmp(def->defname, "column_name") == 0)
01036 {
01037 colname = defGetString(def);
01038 break;
01039 }
01040 }
01041
01042 appendStringInfoString(buf, quote_identifier(colname));
01043
01044 *retrieved_attrs = lappend_int(*retrieved_attrs, i + 1);
01045 }
01046
01047
01048 if (first)
01049 appendStringInfoString(buf, "NULL");
01050
01051
01052
01053
01054 appendStringInfoString(buf, " FROM ");
01055 deparseRelation(buf, rel);
01056 }
01057
01058
01059
01060
01061
01062 static void
01063 deparseColumnRef(StringInfo buf, int varno, int varattno, PlannerInfo *root)
01064 {
01065 RangeTblEntry *rte;
01066 char *colname = NULL;
01067 List *options;
01068 ListCell *lc;
01069
01070
01071 Assert(!IS_SPECIAL_VARNO(varno));
01072
01073
01074 rte = planner_rt_fetch(varno, root);
01075
01076
01077
01078
01079
01080 options = GetForeignColumnOptions(rte->relid, varattno);
01081 foreach(lc, options)
01082 {
01083 DefElem *def = (DefElem *) lfirst(lc);
01084
01085 if (strcmp(def->defname, "column_name") == 0)
01086 {
01087 colname = defGetString(def);
01088 break;
01089 }
01090 }
01091
01092
01093
01094
01095
01096 if (colname == NULL)
01097 colname = get_relid_attribute_name(rte->relid, varattno);
01098
01099 appendStringInfoString(buf, quote_identifier(colname));
01100 }
01101
01102
01103
01104
01105
01106
01107 static void
01108 deparseRelation(StringInfo buf, Relation rel)
01109 {
01110 ForeignTable *table;
01111 const char *nspname = NULL;
01112 const char *relname = NULL;
01113 ListCell *lc;
01114
01115
01116 table = GetForeignTable(RelationGetRelid(rel));
01117
01118
01119
01120
01121 foreach(lc, table->options)
01122 {
01123 DefElem *def = (DefElem *) lfirst(lc);
01124
01125 if (strcmp(def->defname, "schema_name") == 0)
01126 nspname = defGetString(def);
01127 else if (strcmp(def->defname, "table_name") == 0)
01128 relname = defGetString(def);
01129 }
01130
01131
01132
01133
01134
01135 if (nspname == NULL)
01136 nspname = get_namespace_name(RelationGetNamespace(rel));
01137 if (relname == NULL)
01138 relname = RelationGetRelationName(rel);
01139
01140 appendStringInfo(buf, "%s.%s",
01141 quote_identifier(nspname), quote_identifier(relname));
01142 }
01143
01144
01145
01146
01147 static void
01148 deparseStringLiteral(StringInfo buf, const char *val)
01149 {
01150 const char *valptr;
01151
01152
01153
01154
01155
01156
01157
01158 if (strchr(val, '\\') != NULL)
01159 appendStringInfoChar(buf, ESCAPE_STRING_SYNTAX);
01160 appendStringInfoChar(buf, '\'');
01161 for (valptr = val; *valptr; valptr++)
01162 {
01163 char ch = *valptr;
01164
01165 if (SQL_STR_DOUBLE(ch, true))
01166 appendStringInfoChar(buf, ch);
01167 appendStringInfoChar(buf, ch);
01168 }
01169 appendStringInfoChar(buf, '\'');
01170 }
01171
01172
01173
01174
01175
01176
01177
01178
01179
01180
01181
01182 static void
01183 deparseExpr(Expr *node, deparse_expr_cxt *context)
01184 {
01185 if (node == NULL)
01186 return;
01187
01188 switch (nodeTag(node))
01189 {
01190 case T_Var:
01191 deparseVar((Var *) node, context);
01192 break;
01193 case T_Const:
01194 deparseConst((Const *) node, context);
01195 break;
01196 case T_Param:
01197 deparseParam((Param *) node, context);
01198 break;
01199 case T_ArrayRef:
01200 deparseArrayRef((ArrayRef *) node, context);
01201 break;
01202 case T_FuncExpr:
01203 deparseFuncExpr((FuncExpr *) node, context);
01204 break;
01205 case T_OpExpr:
01206 deparseOpExpr((OpExpr *) node, context);
01207 break;
01208 case T_DistinctExpr:
01209 deparseDistinctExpr((DistinctExpr *) node, context);
01210 break;
01211 case T_ScalarArrayOpExpr:
01212 deparseScalarArrayOpExpr((ScalarArrayOpExpr *) node, context);
01213 break;
01214 case T_RelabelType:
01215 deparseRelabelType((RelabelType *) node, context);
01216 break;
01217 case T_BoolExpr:
01218 deparseBoolExpr((BoolExpr *) node, context);
01219 break;
01220 case T_NullTest:
01221 deparseNullTest((NullTest *) node, context);
01222 break;
01223 case T_ArrayExpr:
01224 deparseArrayExpr((ArrayExpr *) node, context);
01225 break;
01226 default:
01227 elog(ERROR, "unsupported expression type for deparse: %d",
01228 (int) nodeTag(node));
01229 break;
01230 }
01231 }
01232
01233
01234
01235
01236
01237
01238
01239
01240
01241 static void
01242 deparseVar(Var *node, deparse_expr_cxt *context)
01243 {
01244 StringInfo buf = context->buf;
01245
01246 if (node->varno == context->foreignrel->relid &&
01247 node->varlevelsup == 0)
01248 {
01249
01250 deparseColumnRef(buf, node->varno, node->varattno, context->root);
01251 }
01252 else
01253 {
01254
01255 if (context->params_list)
01256 {
01257 int pindex = 0;
01258 ListCell *lc;
01259
01260
01261 foreach(lc, *context->params_list)
01262 {
01263 pindex++;
01264 if (equal(node, (Node *) lfirst(lc)))
01265 break;
01266 }
01267 if (lc == NULL)
01268 {
01269
01270 pindex++;
01271 *context->params_list = lappend(*context->params_list, node);
01272 }
01273
01274 appendStringInfo(buf, "$%d", pindex);
01275 appendStringInfo(buf, "::%s",
01276 format_type_with_typemod(node->vartype,
01277 node->vartypmod));
01278 }
01279 else
01280 {
01281 appendStringInfo(buf, "(SELECT null::%s)",
01282 format_type_with_typemod(node->vartype,
01283 node->vartypmod));
01284 }
01285 }
01286 }
01287
01288
01289
01290
01291
01292
01293 static void
01294 deparseConst(Const *node, deparse_expr_cxt *context)
01295 {
01296 StringInfo buf = context->buf;
01297 Oid typoutput;
01298 bool typIsVarlena;
01299 char *extval;
01300 bool isfloat = false;
01301 bool needlabel;
01302
01303 if (node->constisnull)
01304 {
01305 appendStringInfo(buf, "NULL");
01306 appendStringInfo(buf, "::%s",
01307 format_type_with_typemod(node->consttype,
01308 node->consttypmod));
01309 return;
01310 }
01311
01312 getTypeOutputInfo(node->consttype,
01313 &typoutput, &typIsVarlena);
01314 extval = OidOutputFunctionCall(typoutput, node->constvalue);
01315
01316 switch (node->consttype)
01317 {
01318 case INT2OID:
01319 case INT4OID:
01320 case INT8OID:
01321 case OIDOID:
01322 case FLOAT4OID:
01323 case FLOAT8OID:
01324 case NUMERICOID:
01325 {
01326
01327
01328
01329
01330 if (strspn(extval, "0123456789+-eE.") == strlen(extval))
01331 {
01332 if (extval[0] == '+' || extval[0] == '-')
01333 appendStringInfo(buf, "(%s)", extval);
01334 else
01335 appendStringInfoString(buf, extval);
01336 if (strcspn(extval, "eE.") != strlen(extval))
01337 isfloat = true;
01338 }
01339 else
01340 appendStringInfo(buf, "'%s'", extval);
01341 }
01342 break;
01343 case BITOID:
01344 case VARBITOID:
01345 appendStringInfo(buf, "B'%s'", extval);
01346 break;
01347 case BOOLOID:
01348 if (strcmp(extval, "t") == 0)
01349 appendStringInfoString(buf, "true");
01350 else
01351 appendStringInfoString(buf, "false");
01352 break;
01353 default:
01354 deparseStringLiteral(buf, extval);
01355 break;
01356 }
01357
01358
01359
01360
01361
01362
01363
01364
01365 switch (node->consttype)
01366 {
01367 case BOOLOID:
01368 case INT4OID:
01369 case UNKNOWNOID:
01370 needlabel = false;
01371 break;
01372 case NUMERICOID:
01373 needlabel = !isfloat || (node->consttypmod >= 0);
01374 break;
01375 default:
01376 needlabel = true;
01377 break;
01378 }
01379 if (needlabel)
01380 appendStringInfo(buf, "::%s",
01381 format_type_with_typemod(node->consttype,
01382 node->consttypmod));
01383 }
01384
01385
01386
01387
01388
01389
01390
01391
01392
01393
01394
01395
01396
01397
01398
01399
01400
01401
01402
01403
01404
01405 static void
01406 deparseParam(Param *node, deparse_expr_cxt *context)
01407 {
01408 StringInfo buf = context->buf;
01409
01410 if (context->params_list)
01411 {
01412 int pindex = 0;
01413 ListCell *lc;
01414
01415
01416 foreach(lc, *context->params_list)
01417 {
01418 pindex++;
01419 if (equal(node, (Node *) lfirst(lc)))
01420 break;
01421 }
01422 if (lc == NULL)
01423 {
01424
01425 pindex++;
01426 *context->params_list = lappend(*context->params_list, node);
01427 }
01428
01429 appendStringInfo(buf, "$%d", pindex);
01430 appendStringInfo(buf, "::%s",
01431 format_type_with_typemod(node->paramtype,
01432 node->paramtypmod));
01433 }
01434 else
01435 {
01436 appendStringInfo(buf, "(SELECT null::%s)",
01437 format_type_with_typemod(node->paramtype,
01438 node->paramtypmod));
01439 }
01440 }
01441
01442
01443
01444
01445 static void
01446 deparseArrayRef(ArrayRef *node, deparse_expr_cxt *context)
01447 {
01448 StringInfo buf = context->buf;
01449 ListCell *lowlist_item;
01450 ListCell *uplist_item;
01451
01452
01453 appendStringInfoChar(buf, '(');
01454
01455
01456
01457
01458
01459
01460
01461 if (IsA(node->refexpr, Var))
01462 deparseExpr(node->refexpr, context);
01463 else
01464 {
01465 appendStringInfoChar(buf, '(');
01466 deparseExpr(node->refexpr, context);
01467 appendStringInfoChar(buf, ')');
01468 }
01469
01470
01471 lowlist_item = list_head(node->reflowerindexpr);
01472 foreach(uplist_item, node->refupperindexpr)
01473 {
01474 appendStringInfoChar(buf, '[');
01475 if (lowlist_item)
01476 {
01477 deparseExpr(lfirst(lowlist_item), context);
01478 appendStringInfoChar(buf, ':');
01479 lowlist_item = lnext(lowlist_item);
01480 }
01481 deparseExpr(lfirst(uplist_item), context);
01482 appendStringInfoChar(buf, ']');
01483 }
01484
01485 appendStringInfoChar(buf, ')');
01486 }
01487
01488
01489
01490
01491 static void
01492 deparseFuncExpr(FuncExpr *node, deparse_expr_cxt *context)
01493 {
01494 StringInfo buf = context->buf;
01495 HeapTuple proctup;
01496 Form_pg_proc procform;
01497 const char *proname;
01498 bool use_variadic;
01499 bool first;
01500 ListCell *arg;
01501
01502
01503
01504
01505
01506 if (node->funcformat == COERCE_IMPLICIT_CAST)
01507 {
01508 deparseExpr((Expr *) linitial(node->args), context);
01509 return;
01510 }
01511
01512
01513
01514
01515
01516 if (node->funcformat == COERCE_EXPLICIT_CAST)
01517 {
01518 Oid rettype = node->funcresulttype;
01519 int32 coercedTypmod;
01520
01521
01522 (void) exprIsLengthCoercion((Node *) node, &coercedTypmod);
01523
01524 deparseExpr((Expr *) linitial(node->args), context);
01525 appendStringInfo(buf, "::%s",
01526 format_type_with_typemod(rettype, coercedTypmod));
01527 return;
01528 }
01529
01530
01531
01532
01533 proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(node->funcid));
01534 if (!HeapTupleIsValid(proctup))
01535 elog(ERROR, "cache lookup failed for function %u", node->funcid);
01536 procform = (Form_pg_proc) GETSTRUCT(proctup);
01537
01538
01539 if (OidIsValid(procform->provariadic))
01540 {
01541 if (procform->provariadic != ANYOID)
01542 use_variadic = true;
01543 else
01544 use_variadic = node->funcvariadic;
01545 }
01546 else
01547 use_variadic = false;
01548
01549
01550 if (procform->pronamespace != PG_CATALOG_NAMESPACE)
01551 {
01552 const char *schemaname;
01553
01554 schemaname = get_namespace_name(procform->pronamespace);
01555 appendStringInfo(buf, "%s.", quote_identifier(schemaname));
01556 }
01557
01558
01559 proname = NameStr(procform->proname);
01560 appendStringInfo(buf, "%s(", quote_identifier(proname));
01561
01562 first = true;
01563 foreach(arg, node->args)
01564 {
01565 if (!first)
01566 appendStringInfoString(buf, ", ");
01567 if (use_variadic && lnext(arg) == NULL)
01568 appendStringInfoString(buf, "VARIADIC ");
01569 deparseExpr((Expr *) lfirst(arg), context);
01570 first = false;
01571 }
01572 appendStringInfoChar(buf, ')');
01573
01574 ReleaseSysCache(proctup);
01575 }
01576
01577
01578
01579
01580
01581 static void
01582 deparseOpExpr(OpExpr *node, deparse_expr_cxt *context)
01583 {
01584 StringInfo buf = context->buf;
01585 HeapTuple tuple;
01586 Form_pg_operator form;
01587 char oprkind;
01588 ListCell *arg;
01589
01590
01591 tuple = SearchSysCache1(OPEROID, ObjectIdGetDatum(node->opno));
01592 if (!HeapTupleIsValid(tuple))
01593 elog(ERROR, "cache lookup failed for operator %u", node->opno);
01594 form = (Form_pg_operator) GETSTRUCT(tuple);
01595 oprkind = form->oprkind;
01596
01597
01598 Assert((oprkind == 'r' && list_length(node->args) == 1) ||
01599 (oprkind == 'l' && list_length(node->args) == 1) ||
01600 (oprkind == 'b' && list_length(node->args) == 2));
01601
01602
01603 appendStringInfoChar(buf, '(');
01604
01605
01606 if (oprkind == 'r' || oprkind == 'b')
01607 {
01608 arg = list_head(node->args);
01609 deparseExpr(lfirst(arg), context);
01610 appendStringInfoChar(buf, ' ');
01611 }
01612
01613
01614 deparseOperatorName(buf, form);
01615
01616
01617 if (oprkind == 'l' || oprkind == 'b')
01618 {
01619 arg = list_tail(node->args);
01620 appendStringInfoChar(buf, ' ');
01621 deparseExpr(lfirst(arg), context);
01622 }
01623
01624 appendStringInfoChar(buf, ')');
01625
01626 ReleaseSysCache(tuple);
01627 }
01628
01629
01630
01631
01632 static void
01633 deparseOperatorName(StringInfo buf, Form_pg_operator opform)
01634 {
01635 char *opname;
01636
01637
01638 opname = NameStr(opform->oprname);
01639
01640
01641 if (opform->oprnamespace != PG_CATALOG_NAMESPACE)
01642 {
01643 const char *opnspname;
01644
01645 opnspname = get_namespace_name(opform->oprnamespace);
01646
01647 appendStringInfo(buf, "OPERATOR(%s.%s)",
01648 quote_identifier(opnspname), opname);
01649 }
01650 else
01651 {
01652
01653 appendStringInfo(buf, "%s", opname);
01654 }
01655 }
01656
01657
01658
01659
01660 static void
01661 deparseDistinctExpr(DistinctExpr *node, deparse_expr_cxt *context)
01662 {
01663 StringInfo buf = context->buf;
01664
01665 Assert(list_length(node->args) == 2);
01666
01667 appendStringInfoChar(buf, '(');
01668 deparseExpr(linitial(node->args), context);
01669 appendStringInfoString(buf, " IS DISTINCT FROM ");
01670 deparseExpr(lsecond(node->args), context);
01671 appendStringInfoChar(buf, ')');
01672 }
01673
01674
01675
01676
01677
01678 static void
01679 deparseScalarArrayOpExpr(ScalarArrayOpExpr *node, deparse_expr_cxt *context)
01680 {
01681 StringInfo buf = context->buf;
01682 HeapTuple tuple;
01683 Form_pg_operator form;
01684 Expr *arg1;
01685 Expr *arg2;
01686
01687
01688 tuple = SearchSysCache1(OPEROID, ObjectIdGetDatum(node->opno));
01689 if (!HeapTupleIsValid(tuple))
01690 elog(ERROR, "cache lookup failed for operator %u", node->opno);
01691 form = (Form_pg_operator) GETSTRUCT(tuple);
01692
01693
01694 Assert(list_length(node->args) == 2);
01695
01696
01697 appendStringInfoChar(buf, '(');
01698
01699
01700 arg1 = linitial(node->args);
01701 deparseExpr(arg1, context);
01702 appendStringInfoChar(buf, ' ');
01703
01704
01705 deparseOperatorName(buf, form);
01706 appendStringInfo(buf, " %s (", node->useOr ? "ANY" : "ALL");
01707
01708
01709 arg2 = lsecond(node->args);
01710 deparseExpr(arg2, context);
01711
01712 appendStringInfoChar(buf, ')');
01713
01714
01715 appendStringInfoChar(buf, ')');
01716
01717 ReleaseSysCache(tuple);
01718 }
01719
01720
01721
01722
01723 static void
01724 deparseRelabelType(RelabelType *node, deparse_expr_cxt *context)
01725 {
01726 deparseExpr(node->arg, context);
01727 if (node->relabelformat != COERCE_IMPLICIT_CAST)
01728 appendStringInfo(context->buf, "::%s",
01729 format_type_with_typemod(node->resulttype,
01730 node->resulttypmod));
01731 }
01732
01733
01734
01735
01736
01737
01738
01739 static void
01740 deparseBoolExpr(BoolExpr *node, deparse_expr_cxt *context)
01741 {
01742 StringInfo buf = context->buf;
01743 const char *op = NULL;
01744 bool first;
01745 ListCell *lc;
01746
01747 switch (node->boolop)
01748 {
01749 case AND_EXPR:
01750 op = "AND";
01751 break;
01752 case OR_EXPR:
01753 op = "OR";
01754 break;
01755 case NOT_EXPR:
01756 appendStringInfoString(buf, "(NOT ");
01757 deparseExpr(linitial(node->args), context);
01758 appendStringInfoChar(buf, ')');
01759 return;
01760 }
01761
01762 appendStringInfoChar(buf, '(');
01763 first = true;
01764 foreach(lc, node->args)
01765 {
01766 if (!first)
01767 appendStringInfo(buf, " %s ", op);
01768 deparseExpr((Expr *) lfirst(lc), context);
01769 first = false;
01770 }
01771 appendStringInfoChar(buf, ')');
01772 }
01773
01774
01775
01776
01777 static void
01778 deparseNullTest(NullTest *node, deparse_expr_cxt *context)
01779 {
01780 StringInfo buf = context->buf;
01781
01782 appendStringInfoChar(buf, '(');
01783 deparseExpr(node->arg, context);
01784 if (node->nulltesttype == IS_NULL)
01785 appendStringInfoString(buf, " IS NULL)");
01786 else
01787 appendStringInfoString(buf, " IS NOT NULL)");
01788 }
01789
01790
01791
01792
01793 static void
01794 deparseArrayExpr(ArrayExpr *node, deparse_expr_cxt *context)
01795 {
01796 StringInfo buf = context->buf;
01797 bool first = true;
01798 ListCell *lc;
01799
01800 appendStringInfoString(buf, "ARRAY[");
01801 foreach(lc, node->elements)
01802 {
01803 if (!first)
01804 appendStringInfoString(buf, ", ");
01805 deparseExpr(lfirst(lc), context);
01806 first = false;
01807 }
01808 appendStringInfoChar(buf, ']');
01809
01810
01811 if (node->elements == NIL)
01812 appendStringInfo(buf, "::%s",
01813 format_type_with_typemod(node->array_typeid, -1));
01814 }