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 #include "postgres.h"
00027
00028 #include "access/heapam.h"
00029 #include "access/sysattr.h"
00030 #include "catalog/pg_type.h"
00031 #include "nodes/makefuncs.h"
00032 #include "optimizer/prep.h"
00033 #include "optimizer/tlist.h"
00034 #include "parser/parsetree.h"
00035 #include "parser/parse_coerce.h"
00036 #include "utils/rel.h"
00037
00038
00039 static List *expand_targetlist(List *tlist, int command_type,
00040 Index result_relation, List *range_table);
00041
00042
00043
00044
00045
00046
00047
00048
00049 List *
00050 preprocess_targetlist(PlannerInfo *root, List *tlist)
00051 {
00052 Query *parse = root->parse;
00053 int result_relation = parse->resultRelation;
00054 List *range_table = parse->rtable;
00055 CmdType command_type = parse->commandType;
00056 ListCell *lc;
00057
00058
00059
00060
00061
00062 if (result_relation)
00063 {
00064 RangeTblEntry *rte = rt_fetch(result_relation, range_table);
00065
00066 if (rte->subquery != NULL || rte->relid == InvalidOid)
00067 elog(ERROR, "subquery cannot be result relation");
00068 }
00069
00070
00071
00072
00073
00074
00075 if (command_type == CMD_INSERT || command_type == CMD_UPDATE)
00076 tlist = expand_targetlist(tlist, command_type,
00077 result_relation, range_table);
00078
00079
00080
00081
00082
00083
00084 foreach(lc, root->rowMarks)
00085 {
00086 PlanRowMark *rc = (PlanRowMark *) lfirst(lc);
00087 Var *var;
00088 char resname[32];
00089 TargetEntry *tle;
00090
00091
00092 if (rc->rti != rc->prti)
00093 continue;
00094
00095 if (rc->markType != ROW_MARK_COPY)
00096 {
00097
00098 var = makeVar(rc->rti,
00099 SelfItemPointerAttributeNumber,
00100 TIDOID,
00101 -1,
00102 InvalidOid,
00103 0);
00104 snprintf(resname, sizeof(resname), "ctid%u", rc->rowmarkId);
00105 tle = makeTargetEntry((Expr *) var,
00106 list_length(tlist) + 1,
00107 pstrdup(resname),
00108 true);
00109 tlist = lappend(tlist, tle);
00110
00111
00112 if (rc->isParent)
00113 {
00114 var = makeVar(rc->rti,
00115 TableOidAttributeNumber,
00116 OIDOID,
00117 -1,
00118 InvalidOid,
00119 0);
00120 snprintf(resname, sizeof(resname), "tableoid%u", rc->rowmarkId);
00121 tle = makeTargetEntry((Expr *) var,
00122 list_length(tlist) + 1,
00123 pstrdup(resname),
00124 true);
00125 tlist = lappend(tlist, tle);
00126 }
00127 }
00128 else
00129 {
00130
00131 var = makeWholeRowVar(rt_fetch(rc->rti, range_table),
00132 rc->rti,
00133 0,
00134 false);
00135 snprintf(resname, sizeof(resname), "wholerow%u", rc->rowmarkId);
00136 tle = makeTargetEntry((Expr *) var,
00137 list_length(tlist) + 1,
00138 pstrdup(resname),
00139 true);
00140 tlist = lappend(tlist, tle);
00141 }
00142 }
00143
00144
00145
00146
00147
00148
00149
00150
00151 if (parse->returningList && list_length(parse->rtable) > 1)
00152 {
00153 List *vars;
00154 ListCell *l;
00155
00156 vars = pull_var_clause((Node *) parse->returningList,
00157 PVC_RECURSE_AGGREGATES,
00158 PVC_INCLUDE_PLACEHOLDERS);
00159 foreach(l, vars)
00160 {
00161 Var *var = (Var *) lfirst(l);
00162 TargetEntry *tle;
00163
00164 if (IsA(var, Var) &&
00165 var->varno == result_relation)
00166 continue;
00167
00168 if (tlist_member((Node *) var, tlist))
00169 continue;
00170
00171 tle = makeTargetEntry((Expr *) var,
00172 list_length(tlist) + 1,
00173 NULL,
00174 true);
00175
00176 tlist = lappend(tlist, tle);
00177 }
00178 list_free(vars);
00179 }
00180
00181 return tlist;
00182 }
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196 static List *
00197 expand_targetlist(List *tlist, int command_type,
00198 Index result_relation, List *range_table)
00199 {
00200 List *new_tlist = NIL;
00201 ListCell *tlist_item;
00202 Relation rel;
00203 int attrno,
00204 numattrs;
00205
00206 tlist_item = list_head(tlist);
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217 rel = heap_open(getrelid(result_relation, range_table), NoLock);
00218
00219 numattrs = RelationGetNumberOfAttributes(rel);
00220
00221 for (attrno = 1; attrno <= numattrs; attrno++)
00222 {
00223 Form_pg_attribute att_tup = rel->rd_att->attrs[attrno - 1];
00224 TargetEntry *new_tle = NULL;
00225
00226 if (tlist_item != NULL)
00227 {
00228 TargetEntry *old_tle = (TargetEntry *) lfirst(tlist_item);
00229
00230 if (!old_tle->resjunk && old_tle->resno == attrno)
00231 {
00232 new_tle = old_tle;
00233 tlist_item = lnext(tlist_item);
00234 }
00235 }
00236
00237 if (new_tle == NULL)
00238 {
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261 Oid atttype = att_tup->atttypid;
00262 int32 atttypmod = att_tup->atttypmod;
00263 Oid attcollation = att_tup->attcollation;
00264 Node *new_expr;
00265
00266 switch (command_type)
00267 {
00268 case CMD_INSERT:
00269 if (!att_tup->attisdropped)
00270 {
00271 new_expr = (Node *) makeConst(atttype,
00272 -1,
00273 attcollation,
00274 att_tup->attlen,
00275 (Datum) 0,
00276 true,
00277 att_tup->attbyval);
00278 new_expr = coerce_to_domain(new_expr,
00279 InvalidOid, -1,
00280 atttype,
00281 COERCE_IMPLICIT_CAST,
00282 -1,
00283 false,
00284 false);
00285 }
00286 else
00287 {
00288
00289 new_expr = (Node *) makeConst(INT4OID,
00290 -1,
00291 InvalidOid,
00292 sizeof(int32),
00293 (Datum) 0,
00294 true,
00295 true );
00296 }
00297 break;
00298 case CMD_UPDATE:
00299 if (!att_tup->attisdropped)
00300 {
00301 new_expr = (Node *) makeVar(result_relation,
00302 attrno,
00303 atttype,
00304 atttypmod,
00305 attcollation,
00306 0);
00307 }
00308 else
00309 {
00310
00311 new_expr = (Node *) makeConst(INT4OID,
00312 -1,
00313 InvalidOid,
00314 sizeof(int32),
00315 (Datum) 0,
00316 true,
00317 true );
00318 }
00319 break;
00320 default:
00321 elog(ERROR, "unrecognized command_type: %d",
00322 (int) command_type);
00323 new_expr = NULL;
00324 break;
00325 }
00326
00327 new_tle = makeTargetEntry((Expr *) new_expr,
00328 attrno,
00329 pstrdup(NameStr(att_tup->attname)),
00330 false);
00331 }
00332
00333 new_tlist = lappend(new_tlist, new_tle);
00334 }
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344 while (tlist_item)
00345 {
00346 TargetEntry *old_tle = (TargetEntry *) lfirst(tlist_item);
00347
00348 if (!old_tle->resjunk)
00349 elog(ERROR, "targetlist is not sorted correctly");
00350
00351 if (old_tle->resno != attrno)
00352 {
00353 old_tle = flatCopyTargetEntry(old_tle);
00354 old_tle->resno = attrno;
00355 }
00356 new_tlist = lappend(new_tlist, old_tle);
00357 attrno++;
00358 tlist_item = lnext(tlist_item);
00359 }
00360
00361 heap_close(rel, NoLock);
00362
00363 return new_tlist;
00364 }
00365
00366
00367
00368
00369
00370
00371
00372 PlanRowMark *
00373 get_plan_rowmark(List *rowmarks, Index rtindex)
00374 {
00375 ListCell *l;
00376
00377 foreach(l, rowmarks)
00378 {
00379 PlanRowMark *rc = (PlanRowMark *) lfirst(l);
00380
00381 if (rc->rti == rtindex)
00382 return rc;
00383 }
00384 return NULL;
00385 }