| 1 | /*------------------------------------------------------------------------- |
| 2 | * |
| 3 | * preptlist.c |
| 4 | * Routines to preprocess the parse tree target list |
| 5 | * |
| 6 | * For INSERT and UPDATE queries, the targetlist must contain an entry for |
| 7 | * each attribute of the target relation in the correct order. For UPDATE and |
| 8 | * DELETE queries, it must also contain junk tlist entries needed to allow the |
| 9 | * executor to identify the rows to be updated or deleted. For all query |
| 10 | * types, we may need to add junk tlist entries for Vars used in the RETURNING |
| 11 | * list and row ID information needed for SELECT FOR UPDATE locking and/or |
| 12 | * EvalPlanQual checking. |
| 13 | * |
| 14 | * The query rewrite phase also does preprocessing of the targetlist (see |
| 15 | * rewriteTargetListIU). The division of labor between here and there is |
| 16 | * partially historical, but it's not entirely arbitrary. In particular, |
| 17 | * consider an UPDATE across an inheritance tree. What rewriteTargetListIU |
| 18 | * does need be done only once (because it depends only on the properties of |
| 19 | * the parent relation). What's done here has to be done over again for each |
| 20 | * child relation, because it depends on the properties of the child, which |
| 21 | * might be of a different relation type, or have more columns and/or a |
| 22 | * different column order than the parent. |
| 23 | * |
| 24 | * The fact that rewriteTargetListIU sorts non-resjunk tlist entries by column |
| 25 | * position, which expand_targetlist depends on, violates the above comment |
| 26 | * because the sorting is only valid for the parent relation. In inherited |
| 27 | * UPDATE cases, adjust_inherited_tlist runs in between to take care of fixing |
| 28 | * the tlists for child tables to keep expand_targetlist happy. We do it like |
| 29 | * that because it's faster in typical non-inherited cases. |
| 30 | * |
| 31 | * |
| 32 | * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group |
| 33 | * Portions Copyright (c) 1994, Regents of the University of California |
| 34 | * |
| 35 | * IDENTIFICATION |
| 36 | * src/backend/optimizer/prep/preptlist.c |
| 37 | * |
| 38 | *------------------------------------------------------------------------- |
| 39 | */ |
| 40 | |
| 41 | #include "postgres.h" |
| 42 | |
| 43 | #include "access/sysattr.h" |
| 44 | #include "access/table.h" |
| 45 | #include "catalog/pg_type.h" |
| 46 | #include "nodes/makefuncs.h" |
| 47 | #include "optimizer/optimizer.h" |
| 48 | #include "optimizer/prep.h" |
| 49 | #include "optimizer/tlist.h" |
| 50 | #include "parser/parsetree.h" |
| 51 | #include "parser/parse_coerce.h" |
| 52 | #include "rewrite/rewriteHandler.h" |
| 53 | #include "utils/rel.h" |
| 54 | |
| 55 | |
| 56 | static List *expand_targetlist(List *tlist, int command_type, |
| 57 | Index result_relation, Relation rel); |
| 58 | |
| 59 | |
| 60 | /* |
| 61 | * preprocess_targetlist |
| 62 | * Driver for preprocessing the parse tree targetlist. |
| 63 | * |
| 64 | * Returns the new targetlist. |
| 65 | * |
| 66 | * As a side effect, if there's an ON CONFLICT UPDATE clause, its targetlist |
| 67 | * is also preprocessed (and updated in-place). |
| 68 | */ |
| 69 | List * |
| 70 | preprocess_targetlist(PlannerInfo *root) |
| 71 | { |
| 72 | Query *parse = root->parse; |
| 73 | int result_relation = parse->resultRelation; |
| 74 | List *range_table = parse->rtable; |
| 75 | CmdType command_type = parse->commandType; |
| 76 | RangeTblEntry *target_rte = NULL; |
| 77 | Relation target_relation = NULL; |
| 78 | List *tlist; |
| 79 | ListCell *lc; |
| 80 | |
| 81 | /* |
| 82 | * If there is a result relation, open it so we can look for missing |
| 83 | * columns and so on. We assume that previous code already acquired at |
| 84 | * least AccessShareLock on the relation, so we need no lock here. |
| 85 | */ |
| 86 | if (result_relation) |
| 87 | { |
| 88 | target_rte = rt_fetch(result_relation, range_table); |
| 89 | |
| 90 | /* |
| 91 | * Sanity check: it'd better be a real relation not, say, a subquery. |
| 92 | * Else parser or rewriter messed up. |
| 93 | */ |
| 94 | if (target_rte->rtekind != RTE_RELATION) |
| 95 | elog(ERROR, "result relation must be a regular relation" ); |
| 96 | |
| 97 | target_relation = table_open(target_rte->relid, NoLock); |
| 98 | } |
| 99 | else |
| 100 | Assert(command_type == CMD_SELECT); |
| 101 | |
| 102 | /* |
| 103 | * For UPDATE/DELETE, add any junk column(s) needed to allow the executor |
| 104 | * to identify the rows to be updated or deleted. Note that this step |
| 105 | * scribbles on parse->targetList, which is not very desirable, but we |
| 106 | * keep it that way to avoid changing APIs used by FDWs. |
| 107 | */ |
| 108 | if (command_type == CMD_UPDATE || command_type == CMD_DELETE) |
| 109 | rewriteTargetListUD(parse, target_rte, target_relation); |
| 110 | |
| 111 | /* |
| 112 | * for heap_form_tuple to work, the targetlist must match the exact order |
| 113 | * of the attributes. We also need to fill in any missing attributes. -ay |
| 114 | * 10/94 |
| 115 | */ |
| 116 | tlist = parse->targetList; |
| 117 | if (command_type == CMD_INSERT || command_type == CMD_UPDATE) |
| 118 | tlist = expand_targetlist(tlist, command_type, |
| 119 | result_relation, target_relation); |
| 120 | |
| 121 | /* |
| 122 | * Add necessary junk columns for rowmarked rels. These values are needed |
| 123 | * for locking of rels selected FOR UPDATE/SHARE, and to do EvalPlanQual |
| 124 | * rechecking. See comments for PlanRowMark in plannodes.h. If you |
| 125 | * change this stanza, see also expand_inherited_rtentry(), which has to |
| 126 | * be able to add on junk columns equivalent to these. |
| 127 | */ |
| 128 | foreach(lc, root->rowMarks) |
| 129 | { |
| 130 | PlanRowMark *rc = (PlanRowMark *) lfirst(lc); |
| 131 | Var *var; |
| 132 | char resname[32]; |
| 133 | TargetEntry *tle; |
| 134 | |
| 135 | /* child rels use the same junk attrs as their parents */ |
| 136 | if (rc->rti != rc->prti) |
| 137 | continue; |
| 138 | |
| 139 | if (rc->allMarkTypes & ~(1 << ROW_MARK_COPY)) |
| 140 | { |
| 141 | /* Need to fetch TID */ |
| 142 | var = makeVar(rc->rti, |
| 143 | SelfItemPointerAttributeNumber, |
| 144 | TIDOID, |
| 145 | -1, |
| 146 | InvalidOid, |
| 147 | 0); |
| 148 | snprintf(resname, sizeof(resname), "ctid%u" , rc->rowmarkId); |
| 149 | tle = makeTargetEntry((Expr *) var, |
| 150 | list_length(tlist) + 1, |
| 151 | pstrdup(resname), |
| 152 | true); |
| 153 | tlist = lappend(tlist, tle); |
| 154 | } |
| 155 | if (rc->allMarkTypes & (1 << ROW_MARK_COPY)) |
| 156 | { |
| 157 | /* Need the whole row as a junk var */ |
| 158 | var = makeWholeRowVar(rt_fetch(rc->rti, range_table), |
| 159 | rc->rti, |
| 160 | 0, |
| 161 | false); |
| 162 | snprintf(resname, sizeof(resname), "wholerow%u" , rc->rowmarkId); |
| 163 | tle = makeTargetEntry((Expr *) var, |
| 164 | list_length(tlist) + 1, |
| 165 | pstrdup(resname), |
| 166 | true); |
| 167 | tlist = lappend(tlist, tle); |
| 168 | } |
| 169 | |
| 170 | /* If parent of inheritance tree, always fetch the tableoid too. */ |
| 171 | if (rc->isParent) |
| 172 | { |
| 173 | var = makeVar(rc->rti, |
| 174 | TableOidAttributeNumber, |
| 175 | OIDOID, |
| 176 | -1, |
| 177 | InvalidOid, |
| 178 | 0); |
| 179 | snprintf(resname, sizeof(resname), "tableoid%u" , rc->rowmarkId); |
| 180 | tle = makeTargetEntry((Expr *) var, |
| 181 | list_length(tlist) + 1, |
| 182 | pstrdup(resname), |
| 183 | true); |
| 184 | tlist = lappend(tlist, tle); |
| 185 | } |
| 186 | } |
| 187 | |
| 188 | /* |
| 189 | * If the query has a RETURNING list, add resjunk entries for any Vars |
| 190 | * used in RETURNING that belong to other relations. We need to do this |
| 191 | * to make these Vars available for the RETURNING calculation. Vars that |
| 192 | * belong to the result rel don't need to be added, because they will be |
| 193 | * made to refer to the actual heap tuple. |
| 194 | */ |
| 195 | if (parse->returningList && list_length(parse->rtable) > 1) |
| 196 | { |
| 197 | List *vars; |
| 198 | ListCell *l; |
| 199 | |
| 200 | vars = pull_var_clause((Node *) parse->returningList, |
| 201 | PVC_RECURSE_AGGREGATES | |
| 202 | PVC_RECURSE_WINDOWFUNCS | |
| 203 | PVC_INCLUDE_PLACEHOLDERS); |
| 204 | foreach(l, vars) |
| 205 | { |
| 206 | Var *var = (Var *) lfirst(l); |
| 207 | TargetEntry *tle; |
| 208 | |
| 209 | if (IsA(var, Var) && |
| 210 | var->varno == result_relation) |
| 211 | continue; /* don't need it */ |
| 212 | |
| 213 | if (tlist_member((Expr *) var, tlist)) |
| 214 | continue; /* already got it */ |
| 215 | |
| 216 | tle = makeTargetEntry((Expr *) var, |
| 217 | list_length(tlist) + 1, |
| 218 | NULL, |
| 219 | true); |
| 220 | |
| 221 | tlist = lappend(tlist, tle); |
| 222 | } |
| 223 | list_free(vars); |
| 224 | } |
| 225 | |
| 226 | /* |
| 227 | * If there's an ON CONFLICT UPDATE clause, preprocess its targetlist too |
| 228 | * while we have the relation open. |
| 229 | */ |
| 230 | if (parse->onConflict) |
| 231 | parse->onConflict->onConflictSet = |
| 232 | expand_targetlist(parse->onConflict->onConflictSet, |
| 233 | CMD_UPDATE, |
| 234 | result_relation, |
| 235 | target_relation); |
| 236 | |
| 237 | if (target_relation) |
| 238 | table_close(target_relation, NoLock); |
| 239 | |
| 240 | return tlist; |
| 241 | } |
| 242 | |
| 243 | |
| 244 | /***************************************************************************** |
| 245 | * |
| 246 | * TARGETLIST EXPANSION |
| 247 | * |
| 248 | *****************************************************************************/ |
| 249 | |
| 250 | /* |
| 251 | * expand_targetlist |
| 252 | * Given a target list as generated by the parser and a result relation, |
| 253 | * add targetlist entries for any missing attributes, and ensure the |
| 254 | * non-junk attributes appear in proper field order. |
| 255 | */ |
| 256 | static List * |
| 257 | expand_targetlist(List *tlist, int command_type, |
| 258 | Index result_relation, Relation rel) |
| 259 | { |
| 260 | List *new_tlist = NIL; |
| 261 | ListCell *tlist_item; |
| 262 | int attrno, |
| 263 | numattrs; |
| 264 | |
| 265 | tlist_item = list_head(tlist); |
| 266 | |
| 267 | /* |
| 268 | * The rewriter should have already ensured that the TLEs are in correct |
| 269 | * order; but we have to insert TLEs for any missing attributes. |
| 270 | * |
| 271 | * Scan the tuple description in the relation's relcache entry to make |
| 272 | * sure we have all the user attributes in the right order. |
| 273 | */ |
| 274 | numattrs = RelationGetNumberOfAttributes(rel); |
| 275 | |
| 276 | for (attrno = 1; attrno <= numattrs; attrno++) |
| 277 | { |
| 278 | Form_pg_attribute att_tup = TupleDescAttr(rel->rd_att, attrno - 1); |
| 279 | TargetEntry *new_tle = NULL; |
| 280 | |
| 281 | if (tlist_item != NULL) |
| 282 | { |
| 283 | TargetEntry *old_tle = (TargetEntry *) lfirst(tlist_item); |
| 284 | |
| 285 | if (!old_tle->resjunk && old_tle->resno == attrno) |
| 286 | { |
| 287 | new_tle = old_tle; |
| 288 | tlist_item = lnext(tlist_item); |
| 289 | } |
| 290 | } |
| 291 | |
| 292 | if (new_tle == NULL) |
| 293 | { |
| 294 | /* |
| 295 | * Didn't find a matching tlist entry, so make one. |
| 296 | * |
| 297 | * For INSERT, generate a NULL constant. (We assume the rewriter |
| 298 | * would have inserted any available default value.) Also, if the |
| 299 | * column isn't dropped, apply any domain constraints that might |
| 300 | * exist --- this is to catch domain NOT NULL. |
| 301 | * |
| 302 | * For UPDATE, generate a Var reference to the existing value of |
| 303 | * the attribute, so that it gets copied to the new tuple. But |
| 304 | * generate a NULL for dropped columns (we want to drop any old |
| 305 | * values). |
| 306 | * |
| 307 | * When generating a NULL constant for a dropped column, we label |
| 308 | * it INT4 (any other guaranteed-to-exist datatype would do as |
| 309 | * well). We can't label it with the dropped column's datatype |
| 310 | * since that might not exist anymore. It does not really matter |
| 311 | * what we claim the type is, since NULL is NULL --- its |
| 312 | * representation is datatype-independent. This could perhaps |
| 313 | * confuse code comparing the finished plan to the target |
| 314 | * relation, however. |
| 315 | */ |
| 316 | Oid atttype = att_tup->atttypid; |
| 317 | int32 atttypmod = att_tup->atttypmod; |
| 318 | Oid attcollation = att_tup->attcollation; |
| 319 | Node *new_expr; |
| 320 | |
| 321 | switch (command_type) |
| 322 | { |
| 323 | case CMD_INSERT: |
| 324 | if (!att_tup->attisdropped) |
| 325 | { |
| 326 | new_expr = (Node *) makeConst(atttype, |
| 327 | -1, |
| 328 | attcollation, |
| 329 | att_tup->attlen, |
| 330 | (Datum) 0, |
| 331 | true, /* isnull */ |
| 332 | att_tup->attbyval); |
| 333 | new_expr = coerce_to_domain(new_expr, |
| 334 | InvalidOid, -1, |
| 335 | atttype, |
| 336 | COERCION_IMPLICIT, |
| 337 | COERCE_IMPLICIT_CAST, |
| 338 | -1, |
| 339 | false); |
| 340 | } |
| 341 | else |
| 342 | { |
| 343 | /* Insert NULL for dropped column */ |
| 344 | new_expr = (Node *) makeConst(INT4OID, |
| 345 | -1, |
| 346 | InvalidOid, |
| 347 | sizeof(int32), |
| 348 | (Datum) 0, |
| 349 | true, /* isnull */ |
| 350 | true /* byval */ ); |
| 351 | } |
| 352 | break; |
| 353 | case CMD_UPDATE: |
| 354 | if (!att_tup->attisdropped) |
| 355 | { |
| 356 | new_expr = (Node *) makeVar(result_relation, |
| 357 | attrno, |
| 358 | atttype, |
| 359 | atttypmod, |
| 360 | attcollation, |
| 361 | 0); |
| 362 | } |
| 363 | else |
| 364 | { |
| 365 | /* Insert NULL for dropped column */ |
| 366 | new_expr = (Node *) makeConst(INT4OID, |
| 367 | -1, |
| 368 | InvalidOid, |
| 369 | sizeof(int32), |
| 370 | (Datum) 0, |
| 371 | true, /* isnull */ |
| 372 | true /* byval */ ); |
| 373 | } |
| 374 | break; |
| 375 | default: |
| 376 | elog(ERROR, "unrecognized command_type: %d" , |
| 377 | (int) command_type); |
| 378 | new_expr = NULL; /* keep compiler quiet */ |
| 379 | break; |
| 380 | } |
| 381 | |
| 382 | new_tle = makeTargetEntry((Expr *) new_expr, |
| 383 | attrno, |
| 384 | pstrdup(NameStr(att_tup->attname)), |
| 385 | false); |
| 386 | } |
| 387 | |
| 388 | new_tlist = lappend(new_tlist, new_tle); |
| 389 | } |
| 390 | |
| 391 | /* |
| 392 | * The remaining tlist entries should be resjunk; append them all to the |
| 393 | * end of the new tlist, making sure they have resnos higher than the last |
| 394 | * real attribute. (Note: although the rewriter already did such |
| 395 | * renumbering, we have to do it again here in case we are doing an UPDATE |
| 396 | * in a table with dropped columns, or an inheritance child table with |
| 397 | * extra columns.) |
| 398 | */ |
| 399 | while (tlist_item) |
| 400 | { |
| 401 | TargetEntry *old_tle = (TargetEntry *) lfirst(tlist_item); |
| 402 | |
| 403 | if (!old_tle->resjunk) |
| 404 | elog(ERROR, "targetlist is not sorted correctly" ); |
| 405 | /* Get the resno right, but don't copy unnecessarily */ |
| 406 | if (old_tle->resno != attrno) |
| 407 | { |
| 408 | old_tle = flatCopyTargetEntry(old_tle); |
| 409 | old_tle->resno = attrno; |
| 410 | } |
| 411 | new_tlist = lappend(new_tlist, old_tle); |
| 412 | attrno++; |
| 413 | tlist_item = lnext(tlist_item); |
| 414 | } |
| 415 | |
| 416 | return new_tlist; |
| 417 | } |
| 418 | |
| 419 | |
| 420 | /* |
| 421 | * Locate PlanRowMark for given RT index, or return NULL if none |
| 422 | * |
| 423 | * This probably ought to be elsewhere, but there's no very good place |
| 424 | */ |
| 425 | PlanRowMark * |
| 426 | get_plan_rowmark(List *rowmarks, Index rtindex) |
| 427 | { |
| 428 | ListCell *l; |
| 429 | |
| 430 | foreach(l, rowmarks) |
| 431 | { |
| 432 | PlanRowMark *rc = (PlanRowMark *) lfirst(l); |
| 433 | |
| 434 | if (rc->rti == rtindex) |
| 435 | return rc; |
| 436 | } |
| 437 | return NULL; |
| 438 | } |
| 439 | |