1 /*------------------------------------------------------------------------- 2 * 3 * execExprInterp.c 4 * Interpreted evaluation of an expression step list. 5 * 6 * This file provides either a "direct threaded" (for gcc, clang and 7 * compatible) or a "switch threaded" (for all compilers) implementation of 8 * expression evaluation. The former is amongst the fastest known methods 9 * of interpreting programs without resorting to assembly level work, or 10 * just-in-time compilation, but it requires support for computed gotos. 11 * The latter is amongst the fastest approaches doable in standard C. 12 * 13 * In either case we use ExprEvalStep->opcode to dispatch to the code block 14 * within ExecInterpExpr() that implements the specific opcode type. 15 * 16 * Switch-threading uses a plain switch() statement to perform the 17 * dispatch. This has the advantages of being plain C and allowing the 18 * compiler to warn if implementation of a specific opcode has been forgotten. 19 * The disadvantage is that dispatches will, as commonly implemented by 20 * compilers, happen from a single location, requiring more jumps and causing 21 * bad branch prediction. 22 * 23 * In direct threading, we use gcc's label-as-values extension - also adopted 24 * by some other compilers - to replace ExprEvalStep->opcode with the address 25 * of the block implementing the instruction. Dispatch to the next instruction 26 * is done by a "computed goto". This allows for better branch prediction 27 * (as the jumps are happening from different locations) and fewer jumps 28 * (as no preparatory jump to a common dispatch location is needed). 29 * 30 * When using direct threading, ExecReadyInterpretedExpr will replace 31 * each step's opcode field with the address of the relevant code block and 32 * ExprState->flags will contain EEO_FLAG_DIRECT_THREADED to remember that 33 * that's been done. 34 * 35 * For very simple instructions the overhead of the full interpreter 36 * "startup", as minimal as it is, is noticeable. Therefore 37 * ExecReadyInterpretedExpr will choose to implement certain simple 38 * opcode patterns using special fast-path routines (ExecJust*). 39 * 40 * Complex or uncommon instructions are not implemented in-line in 41 * ExecInterpExpr(), rather we call out to a helper function appearing later 42 * in this file. For one reason, there'd not be a noticeable performance 43 * benefit, but more importantly those complex routines are intended to be 44 * shared between different expression evaluation approaches. For instance 45 * a JIT compiler would generate calls to them. (This is why they are 46 * exported rather than being "static" in this file.) 47 * 48 * 49 * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group 50 * Portions Copyright (c) 1994, Regents of the University of California 51 * 52 * IDENTIFICATION 53 * src/backend/executor/execExprInterp.c 54 * 55 *------------------------------------------------------------------------- 56 */ 57 #include "postgres.h" 58 59 #include "access/tuptoaster.h" 60 #include "catalog/pg_type.h" 61 #include "commands/sequence.h" 62 #include "executor/execExpr.h" 63 #include "executor/nodeSubplan.h" 64 #include "funcapi.h" 65 #include "utils/memutils.h" 66 #include "miscadmin.h" 67 #include "nodes/nodeFuncs.h" 68 #include "parser/parsetree.h" 69 #include "pgstat.h" 70 #include "utils/builtins.h" 71 #include "utils/date.h" 72 #include "utils/datum.h" 73 #include "utils/expandedrecord.h" 74 #include "utils/lsyscache.h" 75 #include "utils/timestamp.h" 76 #include "utils/typcache.h" 77 #include "utils/xml.h" 78 79 80 /* 81 * Use computed-goto-based opcode dispatch when computed gotos are available. 82 * But use a separate symbol so that it's easy to adjust locally in this file 83 * for development and testing. 84 */ 85 #ifdef HAVE_COMPUTED_GOTO 86 #define EEO_USE_COMPUTED_GOTO 87 #endif /* HAVE_COMPUTED_GOTO */ 88 89 /* 90 * Macros for opcode dispatch. 91 * 92 * EEO_SWITCH - just hides the switch if not in use. 93 * EEO_CASE - labels the implementation of named expression step type. 94 * EEO_DISPATCH - jump to the implementation of the step type for 'op'. 95 * EEO_OPCODE - compute opcode required by used expression evaluation method. 96 * EEO_NEXT - increment 'op' and jump to correct next step type. 97 * EEO_JUMP - jump to the specified step number within the current expression. 98 */ 99 #if defined(EEO_USE_COMPUTED_GOTO) 100 101 /* struct for jump target -> opcode lookup table */ 102 typedef struct ExprEvalOpLookup 103 { 104 const void *opcode; 105 ExprEvalOp op; 106 } ExprEvalOpLookup; 107 108 /* to make dispatch_table accessible outside ExecInterpExpr() */ 109 static const void **dispatch_table = NULL; 110 111 /* jump target -> opcode lookup table */ 112 static ExprEvalOpLookup reverse_dispatch_table[EEOP_LAST]; 113 114 #define EEO_SWITCH() 115 #define EEO_CASE(name) CASE_##name: 116 #define EEO_DISPATCH() goto *((void *) op->opcode) 117 #define EEO_OPCODE(opcode) ((intptr_t) dispatch_table[opcode]) 118 119 #else /* !EEO_USE_COMPUTED_GOTO */ 120 121 #define EEO_SWITCH() starteval: switch ((ExprEvalOp) op->opcode) 122 #define EEO_CASE(name) case name: 123 #define EEO_DISPATCH() goto starteval 124 #define EEO_OPCODE(opcode) (opcode) 125 126 #endif /* EEO_USE_COMPUTED_GOTO */ 127 128 #define EEO_NEXT() \ 129 do { \ 130 op++; \ 131 EEO_DISPATCH(); \ 132 } while (0) 133 134 #define EEO_JUMP(stepno) \ 135 do { \ 136 op = &state->steps[stepno]; \ 137 EEO_DISPATCH(); \ 138 } while (0) 139 140 141 static Datum ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull); 142 static void ExecInitInterpreter(void); 143 144 /* support functions */ 145 static void CheckVarSlotCompatibility(TupleTableSlot *slot, int attnum, Oid vartype); 146 static void CheckOpSlotCompatibility(ExprEvalStep *op, TupleTableSlot *slot); 147 static TupleDesc get_cached_rowtype(Oid type_id, int32 typmod, 148 ExprEvalRowtypeCache *rowcache, 149 bool *changed); 150 static void ExecEvalRowNullInt(ExprState *state, ExprEvalStep *op, 151 ExprContext *econtext, bool checkisnull); 152 153 /* fast-path evaluation functions */ 154 static Datum ExecJustInnerVar(ExprState *state, ExprContext *econtext, bool *isnull); 155 static Datum ExecJustOuterVar(ExprState *state, ExprContext *econtext, bool *isnull); 156 static Datum ExecJustScanVar(ExprState *state, ExprContext *econtext, bool *isnull); 157 static Datum ExecJustConst(ExprState *state, ExprContext *econtext, bool *isnull); 158 static Datum ExecJustAssignInnerVar(ExprState *state, ExprContext *econtext, bool *isnull); 159 static Datum ExecJustAssignOuterVar(ExprState *state, ExprContext *econtext, bool *isnull); 160 static Datum ExecJustAssignScanVar(ExprState *state, ExprContext *econtext, bool *isnull); 161 static Datum ExecJustApplyFuncToCase(ExprState *state, ExprContext *econtext, bool *isnull); 162 163 164 /* 165 * Prepare ExprState for interpreted execution. 166 */ 167 void 168 ExecReadyInterpretedExpr(ExprState *state) 169 { 170 /* Ensure one-time interpreter setup has been done */ 171 ExecInitInterpreter(); 172 173 /* Simple validity checks on expression */ 174 Assert(state->steps_len >= 1); 175 Assert(state->steps[state->steps_len - 1].opcode == EEOP_DONE); 176 177 /* 178 * Don't perform redundant initialization. This is unreachable in current 179 * cases, but might be hit if there's additional expression evaluation 180 * methods that rely on interpreted execution to work. 181 */ 182 if (state->flags & EEO_FLAG_INTERPRETER_INITIALIZED) 183 return; 184 185 /* 186 * First time through, check whether attribute matches Var. Might not be 187 * ok anymore, due to schema changes. We do that by setting up a callback 188 * that does checking on the first call, which then sets the evalfunc 189 * callback to the actual method of execution. 190 */ 191 state->evalfunc = ExecInterpExprStillValid; 192 193 /* DIRECT_THREADED should not already be set */ 194 Assert((state->flags & EEO_FLAG_DIRECT_THREADED) == 0); 195 196 /* 197 * There shouldn't be any errors before the expression is fully 198 * initialized, and even if so, it'd lead to the expression being 199 * abandoned. So we can set the flag now and save some code. 200 */ 201 state->flags |= EEO_FLAG_INTERPRETER_INITIALIZED; 202 203 /* 204 * Select fast-path evalfuncs for very simple expressions. "Starting up" 205 * the full interpreter is a measurable overhead for these, and these 206 * patterns occur often enough to be worth optimizing. 207 */ 208 if (state->steps_len == 3) 209 { 210 ExprEvalOp step0 = state->steps[0].opcode; 211 ExprEvalOp step1 = state->steps[1].opcode; 212 213 if (step0 == EEOP_INNER_FETCHSOME && 214 step1 == EEOP_INNER_VAR) 215 { 216 state->evalfunc_private = (void *) ExecJustInnerVar; 217 return; 218 } 219 else if (step0 == EEOP_OUTER_FETCHSOME && 220 step1 == EEOP_OUTER_VAR) 221 { 222 state->evalfunc_private = (void *) ExecJustOuterVar; 223 return; 224 } 225 else if (step0 == EEOP_SCAN_FETCHSOME && 226 step1 == EEOP_SCAN_VAR) 227 { 228 state->evalfunc_private = (void *) ExecJustScanVar; 229 return; 230 } 231 else if (step0 == EEOP_INNER_FETCHSOME && 232 step1 == EEOP_ASSIGN_INNER_VAR) 233 { 234 state->evalfunc_private = (void *) ExecJustAssignInnerVar; 235 return; 236 } 237 else if (step0 == EEOP_OUTER_FETCHSOME && 238 step1 == EEOP_ASSIGN_OUTER_VAR) 239 { 240 state->evalfunc_private = (void *) ExecJustAssignOuterVar; 241 return; 242 } 243 else if (step0 == EEOP_SCAN_FETCHSOME && 244 step1 == EEOP_ASSIGN_SCAN_VAR) 245 { 246 state->evalfunc_private = (void *) ExecJustAssignScanVar; 247 return; 248 } 249 else if (step0 == EEOP_CASE_TESTVAL && 250 step1 == EEOP_FUNCEXPR_STRICT && 251 state->steps[0].d.casetest.value) 252 { 253 state->evalfunc_private = (void *) ExecJustApplyFuncToCase; 254 return; 255 } 256 } 257 else if (state->steps_len == 2 && 258 state->steps[0].opcode == EEOP_CONST) 259 { 260 state->evalfunc_private = (void *) ExecJustConst; 261 return; 262 } 263 264 #if defined(EEO_USE_COMPUTED_GOTO) 265 266 /* 267 * In the direct-threaded implementation, replace each opcode with the 268 * address to jump to. (Use ExecEvalStepOp() to get back the opcode.) 269 */ 270 { 271 int off; 272 273 for (off = 0; off < state->steps_len; off++) 274 { 275 ExprEvalStep *op = &state->steps[off]; 276 277 op->opcode = EEO_OPCODE(op->opcode); 278 } 279 280 state->flags |= EEO_FLAG_DIRECT_THREADED; 281 } 282 #endif /* EEO_USE_COMPUTED_GOTO */ 283 284 state->evalfunc_private = (void *) ExecInterpExpr; 285 } 286 287 288 /* 289 * Evaluate expression identified by "state" in the execution context 290 * given by "econtext". *isnull is set to the is-null flag for the result, 291 * and the Datum value is the function result. 292 * 293 * As a special case, return the dispatch table's address if state is NULL. 294 * This is used by ExecInitInterpreter to set up the dispatch_table global. 295 * (Only applies when EEO_USE_COMPUTED_GOTO is defined.) 296 */ 297 static Datum 298 ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull) 299 { 300 ExprEvalStep *op; 301 TupleTableSlot *resultslot; 302 TupleTableSlot *innerslot; 303 TupleTableSlot *outerslot; 304 TupleTableSlot *scanslot; 305 306 /* 307 * This array has to be in the same order as enum ExprEvalOp. 308 */ 309 #if defined(EEO_USE_COMPUTED_GOTO) 310 static const void *const dispatch_table[] = { 311 &&CASE_EEOP_DONE, 312 &&CASE_EEOP_INNER_FETCHSOME, 313 &&CASE_EEOP_OUTER_FETCHSOME, 314 &&CASE_EEOP_SCAN_FETCHSOME, 315 &&CASE_EEOP_INNER_VAR, 316 &&CASE_EEOP_OUTER_VAR, 317 &&CASE_EEOP_SCAN_VAR, 318 &&CASE_EEOP_INNER_SYSVAR, 319 &&CASE_EEOP_OUTER_SYSVAR, 320 &&CASE_EEOP_SCAN_SYSVAR, 321 &&CASE_EEOP_WHOLEROW, 322 &&CASE_EEOP_ASSIGN_INNER_VAR, 323 &&CASE_EEOP_ASSIGN_OUTER_VAR, 324 &&CASE_EEOP_ASSIGN_SCAN_VAR, 325 &&CASE_EEOP_ASSIGN_TMP, 326 &&CASE_EEOP_ASSIGN_TMP_MAKE_RO, 327 &&CASE_EEOP_CONST, 328 &&CASE_EEOP_FUNCEXPR, 329 &&CASE_EEOP_FUNCEXPR_STRICT, 330 &&CASE_EEOP_FUNCEXPR_FUSAGE, 331 &&CASE_EEOP_FUNCEXPR_STRICT_FUSAGE, 332 &&CASE_EEOP_BOOL_AND_STEP_FIRST, 333 &&CASE_EEOP_BOOL_AND_STEP, 334 &&CASE_EEOP_BOOL_AND_STEP_LAST, 335 &&CASE_EEOP_BOOL_OR_STEP_FIRST, 336 &&CASE_EEOP_BOOL_OR_STEP, 337 &&CASE_EEOP_BOOL_OR_STEP_LAST, 338 &&CASE_EEOP_BOOL_NOT_STEP, 339 &&CASE_EEOP_QUAL, 340 &&CASE_EEOP_JUMP, 341 &&CASE_EEOP_JUMP_IF_NULL, 342 &&CASE_EEOP_JUMP_IF_NOT_NULL, 343 &&CASE_EEOP_JUMP_IF_NOT_TRUE, 344 &&CASE_EEOP_NULLTEST_ISNULL, 345 &&CASE_EEOP_NULLTEST_ISNOTNULL, 346 &&CASE_EEOP_NULLTEST_ROWISNULL, 347 &&CASE_EEOP_NULLTEST_ROWISNOTNULL, 348 &&CASE_EEOP_BOOLTEST_IS_TRUE, 349 &&CASE_EEOP_BOOLTEST_IS_NOT_TRUE, 350 &&CASE_EEOP_BOOLTEST_IS_FALSE, 351 &&CASE_EEOP_BOOLTEST_IS_NOT_FALSE, 352 &&CASE_EEOP_PARAM_EXEC, 353 &&CASE_EEOP_PARAM_EXTERN, 354 &&CASE_EEOP_PARAM_CALLBACK, 355 &&CASE_EEOP_CASE_TESTVAL, 356 &&CASE_EEOP_MAKE_READONLY, 357 &&CASE_EEOP_IOCOERCE, 358 &&CASE_EEOP_DISTINCT, 359 &&CASE_EEOP_NOT_DISTINCT, 360 &&CASE_EEOP_NULLIF, 361 &&CASE_EEOP_SQLVALUEFUNCTION, 362 &&CASE_EEOP_CURRENTOFEXPR, 363 &&CASE_EEOP_NEXTVALUEEXPR, 364 &&CASE_EEOP_ARRAYEXPR, 365 &&CASE_EEOP_ARRAYCOERCE, 366 &&CASE_EEOP_ROW, 367 &&CASE_EEOP_ROWCOMPARE_STEP, 368 &&CASE_EEOP_ROWCOMPARE_FINAL, 369 &&CASE_EEOP_MINMAX, 370 &&CASE_EEOP_FIELDSELECT, 371 &&CASE_EEOP_FIELDSTORE_DEFORM, 372 &&CASE_EEOP_FIELDSTORE_FORM, 373 &&CASE_EEOP_SBSREF_SUBSCRIPT, 374 &&CASE_EEOP_SBSREF_OLD, 375 &&CASE_EEOP_SBSREF_ASSIGN, 376 &&CASE_EEOP_SBSREF_FETCH, 377 &&CASE_EEOP_DOMAIN_TESTVAL, 378 &&CASE_EEOP_DOMAIN_NOTNULL, 379 &&CASE_EEOP_DOMAIN_CHECK, 380 &&CASE_EEOP_CONVERT_ROWTYPE, 381 &&CASE_EEOP_SCALARARRAYOP, 382 &&CASE_EEOP_XMLEXPR, 383 &&CASE_EEOP_AGGREF, 384 &&CASE_EEOP_GROUPING_FUNC, 385 &&CASE_EEOP_WINDOW_FUNC, 386 &&CASE_EEOP_SUBPLAN, 387 &&CASE_EEOP_ALTERNATIVE_SUBPLAN, 388 &&CASE_EEOP_AGG_STRICT_DESERIALIZE, 389 &&CASE_EEOP_AGG_DESERIALIZE, 390 &&CASE_EEOP_AGG_STRICT_INPUT_CHECK_ARGS, 391 &&CASE_EEOP_AGG_STRICT_INPUT_CHECK_NULLS, 392 &&CASE_EEOP_AGG_INIT_TRANS, 393 &&CASE_EEOP_AGG_STRICT_TRANS_CHECK, 394 &&CASE_EEOP_AGG_PLAIN_TRANS_BYVAL, 395 &&CASE_EEOP_AGG_PLAIN_TRANS, 396 &&CASE_EEOP_AGG_ORDERED_TRANS_DATUM, 397 &&CASE_EEOP_AGG_ORDERED_TRANS_TUPLE, 398 &&CASE_EEOP_LAST 399 }; 400 401 StaticAssertStmt(EEOP_LAST + 1 == lengthof(dispatch_table), 402 "dispatch_table out of whack with ExprEvalOp"); 403 404 if (unlikely(state == NULL)) 405 return PointerGetDatum(dispatch_table); 406 #else 407 Assert(state != NULL); 408 #endif /* EEO_USE_COMPUTED_GOTO */ 409 410 /* setup state */ 411 op = state->steps; 412 resultslot = state->resultslot; 413 innerslot = econtext->ecxt_innertuple; 414 outerslot = econtext->ecxt_outertuple; 415 scanslot = econtext->ecxt_scantuple; 416 417 #if defined(EEO_USE_COMPUTED_GOTO) 418 EEO_DISPATCH(); 419 #endif 420 421 EEO_SWITCH() 422 { 423 EEO_CASE(EEOP_DONE) 424 { 425 goto out; 426 } 427 428 EEO_CASE(EEOP_INNER_FETCHSOME) 429 { 430 CheckOpSlotCompatibility(op, innerslot); 431 432 slot_getsomeattrs(innerslot, op->d.fetch.last_var); 433 434 EEO_NEXT(); 435 } 436 437 EEO_CASE(EEOP_OUTER_FETCHSOME) 438 { 439 CheckOpSlotCompatibility(op, outerslot); 440 441 slot_getsomeattrs(outerslot, op->d.fetch.last_var); 442 443 EEO_NEXT(); 444 } 445 446 EEO_CASE(EEOP_SCAN_FETCHSOME) 447 { 448 CheckOpSlotCompatibility(op, scanslot); 449 450 slot_getsomeattrs(scanslot, op->d.fetch.last_var); 451 452 EEO_NEXT(); 453 } 454 455 EEO_CASE(EEOP_INNER_VAR) 456 { 457 int attnum = op->d.var.attnum; 458 459 /* 460 * Since we already extracted all referenced columns from the 461 * tuple with a FETCHSOME step, we can just grab the value 462 * directly out of the slot's decomposed-data arrays. But let's 463 * have an Assert to check that that did happen. 464 */ 465 Assert(attnum >= 0 && attnum < innerslot->tts_nvalid); 466 *op->resvalue = innerslot->tts_values[attnum]; 467 *op->resnull = innerslot->tts_isnull[attnum]; 468 469 EEO_NEXT(); 470 } 471 472 EEO_CASE(EEOP_OUTER_VAR) 473 { 474 int attnum = op->d.var.attnum; 475 476 /* See EEOP_INNER_VAR comments */ 477 478 Assert(attnum >= 0 && attnum < outerslot->tts_nvalid); 479 *op->resvalue = outerslot->tts_values[attnum]; 480 *op->resnull = outerslot->tts_isnull[attnum]; 481 482 EEO_NEXT(); 483 } 484 485 EEO_CASE(EEOP_SCAN_VAR) 486 { 487 int attnum = op->d.var.attnum; 488 489 /* See EEOP_INNER_VAR comments */ 490 491 Assert(attnum >= 0 && attnum < scanslot->tts_nvalid); 492 *op->resvalue = scanslot->tts_values[attnum]; 493 *op->resnull = scanslot->tts_isnull[attnum]; 494 495 EEO_NEXT(); 496 } 497 498 EEO_CASE(EEOP_INNER_SYSVAR) 499 { 500 ExecEvalSysVar(state, op, econtext, innerslot); 501 EEO_NEXT(); 502 } 503 504 EEO_CASE(EEOP_OUTER_SYSVAR) 505 { 506 ExecEvalSysVar(state, op, econtext, outerslot); 507 EEO_NEXT(); 508 } 509 510 EEO_CASE(EEOP_SCAN_SYSVAR) 511 { 512 ExecEvalSysVar(state, op, econtext, scanslot); 513 EEO_NEXT(); 514 } 515 516 EEO_CASE(EEOP_WHOLEROW) 517 { 518 /* too complex for an inline implementation */ 519 ExecEvalWholeRowVar(state, op, econtext); 520 521 EEO_NEXT(); 522 } 523 524 EEO_CASE(EEOP_ASSIGN_INNER_VAR) 525 { 526 int resultnum = op->d.assign_var.resultnum; 527 int attnum = op->d.assign_var.attnum; 528 529 /* 530 * We do not need CheckVarSlotCompatibility here; that was taken 531 * care of at compilation time. But see EEOP_INNER_VAR comments. 532 */ 533 Assert(attnum >= 0 && attnum < innerslot->tts_nvalid); 534 Assert(resultnum >= 0 && resultnum < resultslot->tts_tupleDescriptor->natts); 535 resultslot->tts_values[resultnum] = innerslot->tts_values[attnum]; 536 resultslot->tts_isnull[resultnum] = innerslot->tts_isnull[attnum]; 537 538 EEO_NEXT(); 539 } 540 541 EEO_CASE(EEOP_ASSIGN_OUTER_VAR) 542 { 543 int resultnum = op->d.assign_var.resultnum; 544 int attnum = op->d.assign_var.attnum; 545 546 /* 547 * We do not need CheckVarSlotCompatibility here; that was taken 548 * care of at compilation time. But see EEOP_INNER_VAR comments. 549 */ 550 Assert(attnum >= 0 && attnum < outerslot->tts_nvalid); 551 Assert(resultnum >= 0 && resultnum < resultslot->tts_tupleDescriptor->natts); 552 resultslot->tts_values[resultnum] = outerslot->tts_values[attnum]; 553 resultslot->tts_isnull[resultnum] = outerslot->tts_isnull[attnum]; 554 555 EEO_NEXT(); 556 } 557 558 EEO_CASE(EEOP_ASSIGN_SCAN_VAR) 559 { 560 int resultnum = op->d.assign_var.resultnum; 561 int attnum = op->d.assign_var.attnum; 562 563 /* 564 * We do not need CheckVarSlotCompatibility here; that was taken 565 * care of at compilation time. But see EEOP_INNER_VAR comments. 566 */ 567 Assert(attnum >= 0 && attnum < scanslot->tts_nvalid); 568 Assert(resultnum >= 0 && resultnum < resultslot->tts_tupleDescriptor->natts); 569 resultslot->tts_values[resultnum] = scanslot->tts_values[attnum]; 570 resultslot->tts_isnull[resultnum] = scanslot->tts_isnull[attnum]; 571 572 EEO_NEXT(); 573 } 574 575 EEO_CASE(EEOP_ASSIGN_TMP) 576 { 577 int resultnum = op->d.assign_tmp.resultnum; 578 579 Assert(resultnum >= 0 && resultnum < resultslot->tts_tupleDescriptor->natts); 580 resultslot->tts_values[resultnum] = state->resvalue; 581 resultslot->tts_isnull[resultnum] = state->resnull; 582 583 EEO_NEXT(); 584 } 585 586 EEO_CASE(EEOP_ASSIGN_TMP_MAKE_RO) 587 { 588 int resultnum = op->d.assign_tmp.resultnum; 589 590 Assert(resultnum >= 0 && resultnum < resultslot->tts_tupleDescriptor->natts); 591 resultslot->tts_isnull[resultnum] = state->resnull; 592 if (!resultslot->tts_isnull[resultnum]) 593 resultslot->tts_values[resultnum] = 594 MakeExpandedObjectReadOnlyInternal(state->resvalue); 595 else 596 resultslot->tts_values[resultnum] = state->resvalue; 597 598 EEO_NEXT(); 599 } 600 601 EEO_CASE(EEOP_CONST) 602 { 603 *op->resnull = op->d.constval.isnull; 604 *op->resvalue = op->d.constval.value; 605 606 EEO_NEXT(); 607 } 608 609 /* 610 * Function-call implementations. Arguments have previously been 611 * evaluated directly into fcinfo->args. 612 * 613 * As both STRICT checks and function-usage are noticeable performance 614 * wise, and function calls are a very hot-path (they also back 615 * operators!), it's worth having so many separate opcodes. 616 * 617 * Note: the reason for using a temporary variable "d", here and in 618 * other places, is that some compilers think "*op->resvalue = f();" 619 * requires them to evaluate op->resvalue into a register before 620 * calling f(), just in case f() is able to modify op->resvalue 621 * somehow. The extra line of code can save a useless register spill 622 * and reload across the function call. 623 */ 624 EEO_CASE(EEOP_FUNCEXPR) 625 { 626 FunctionCallInfo fcinfo = op->d.func.fcinfo_data; 627 Datum d; 628 629 fcinfo->isnull = false; 630 d = op->d.func.fn_addr(fcinfo); 631 *op->resvalue = d; 632 *op->resnull = fcinfo->isnull; 633 634 EEO_NEXT(); 635 } 636 637 EEO_CASE(EEOP_FUNCEXPR_STRICT) 638 { 639 FunctionCallInfo fcinfo = op->d.func.fcinfo_data; 640 NullableDatum *args = fcinfo->args; 641 int argno; 642 Datum d; 643 644 /* strict function, so check for NULL args */ 645 for (argno = 0; argno < op->d.func.nargs; argno++) 646 { 647 if (args[argno].isnull) 648 { 649 *op->resnull = true; 650 goto strictfail; 651 } 652 } 653 fcinfo->isnull = false; 654 d = op->d.func.fn_addr(fcinfo); 655 *op->resvalue = d; 656 *op->resnull = fcinfo->isnull; 657 658 strictfail: 659 EEO_NEXT(); 660 } 661 662 EEO_CASE(EEOP_FUNCEXPR_FUSAGE) 663 { 664 /* not common enough to inline */ 665 ExecEvalFuncExprFusage(state, op, econtext); 666 667 EEO_NEXT(); 668 } 669 670 EEO_CASE(EEOP_FUNCEXPR_STRICT_FUSAGE) 671 { 672 /* not common enough to inline */ 673 ExecEvalFuncExprStrictFusage(state, op, econtext); 674 675 EEO_NEXT(); 676 } 677 678 /* 679 * If any of its clauses is FALSE, an AND's result is FALSE regardless 680 * of the states of the rest of the clauses, so we can stop evaluating 681 * and return FALSE immediately. If none are FALSE and one or more is 682 * NULL, we return NULL; otherwise we return TRUE. This makes sense 683 * when you interpret NULL as "don't know": perhaps one of the "don't 684 * knows" would have been FALSE if we'd known its value. Only when 685 * all the inputs are known to be TRUE can we state confidently that 686 * the AND's result is TRUE. 687 */ 688 EEO_CASE(EEOP_BOOL_AND_STEP_FIRST) 689 { 690 *op->d.boolexpr.anynull = false; 691 692 /* 693 * EEOP_BOOL_AND_STEP_FIRST resets anynull, otherwise it's the 694 * same as EEOP_BOOL_AND_STEP - so fall through to that. 695 */ 696 697 /* FALL THROUGH */ 698 } 699 700 EEO_CASE(EEOP_BOOL_AND_STEP) 701 { 702 if (*op->resnull) 703 { 704 *op->d.boolexpr.anynull = true; 705 } 706 else if (!DatumGetBool(*op->resvalue)) 707 { 708 /* result is already set to FALSE, need not change it */ 709 /* bail out early */ 710 EEO_JUMP(op->d.boolexpr.jumpdone); 711 } 712 713 EEO_NEXT(); 714 } 715 716 EEO_CASE(EEOP_BOOL_AND_STEP_LAST) 717 { 718 if (*op->resnull) 719 { 720 /* result is already set to NULL, need not change it */ 721 } 722 else if (!DatumGetBool(*op->resvalue)) 723 { 724 /* result is already set to FALSE, need not change it */ 725 726 /* 727 * No point jumping early to jumpdone - would be same target 728 * (as this is the last argument to the AND expression), 729 * except more expensive. 730 */ 731 } 732 else if (*op->d.boolexpr.anynull) 733 { 734 *op->resvalue = (Datum) 0; 735 *op->resnull = true; 736 } 737 else 738 { 739 /* result is already set to TRUE, need not change it */ 740 } 741 742 EEO_NEXT(); 743 } 744 745 /* 746 * If any of its clauses is TRUE, an OR's result is TRUE regardless of 747 * the states of the rest of the clauses, so we can stop evaluating 748 * and return TRUE immediately. If none are TRUE and one or more is 749 * NULL, we return NULL; otherwise we return FALSE. This makes sense 750 * when you interpret NULL as "don't know": perhaps one of the "don't 751 * knows" would have been TRUE if we'd known its value. Only when all 752 * the inputs are known to be FALSE can we state confidently that the 753 * OR's result is FALSE. 754 */ 755 EEO_CASE(EEOP_BOOL_OR_STEP_FIRST) 756 { 757 *op->d.boolexpr.anynull = false; 758 759 /* 760 * EEOP_BOOL_OR_STEP_FIRST resets anynull, otherwise it's the same 761 * as EEOP_BOOL_OR_STEP - so fall through to that. 762 */ 763 764 /* FALL THROUGH */ 765 } 766 767 EEO_CASE(EEOP_BOOL_OR_STEP) 768 { 769 if (*op->resnull) 770 { 771 *op->d.boolexpr.anynull = true; 772 } 773 else if (DatumGetBool(*op->resvalue)) 774 { 775 /* result is already set to TRUE, need not change it */ 776 /* bail out early */ 777 EEO_JUMP(op->d.boolexpr.jumpdone); 778 } 779 780 EEO_NEXT(); 781 } 782 783 EEO_CASE(EEOP_BOOL_OR_STEP_LAST) 784 { 785 if (*op->resnull) 786 { 787 /* result is already set to NULL, need not change it */ 788 } 789 else if (DatumGetBool(*op->resvalue)) 790 { 791 /* result is already set to TRUE, need not change it */ 792 793 /* 794 * No point jumping to jumpdone - would be same target (as 795 * this is the last argument to the AND expression), except 796 * more expensive. 797 */ 798 } 799 else if (*op->d.boolexpr.anynull) 800 { 801 *op->resvalue = (Datum) 0; 802 *op->resnull = true; 803 } 804 else 805 { 806 /* result is already set to FALSE, need not change it */ 807 } 808 809 EEO_NEXT(); 810 } 811 812 EEO_CASE(EEOP_BOOL_NOT_STEP) 813 { 814 /* 815 * Evaluation of 'not' is simple... if expr is false, then return 816 * 'true' and vice versa. It's safe to do this even on a 817 * nominally null value, so we ignore resnull; that means that 818 * NULL in produces NULL out, which is what we want. 819 */ 820 *op->resvalue = BoolGetDatum(!DatumGetBool(*op->resvalue)); 821 822 EEO_NEXT(); 823 } 824 825 EEO_CASE(EEOP_QUAL) 826 { 827 /* simplified version of BOOL_AND_STEP for use by ExecQual() */ 828 829 /* If argument (also result) is false or null ... */ 830 if (*op->resnull || 831 !DatumGetBool(*op->resvalue)) 832 { 833 /* ... bail out early, returning FALSE */ 834 *op->resnull = false; 835 *op->resvalue = BoolGetDatum(false); 836 EEO_JUMP(op->d.qualexpr.jumpdone); 837 } 838 839 /* 840 * Otherwise, leave the TRUE value in place, in case this is the 841 * last qual. Then, TRUE is the correct answer. 842 */ 843 844 EEO_NEXT(); 845 } 846 847 EEO_CASE(EEOP_JUMP) 848 { 849 /* Unconditionally jump to target step */ 850 EEO_JUMP(op->d.jump.jumpdone); 851 } 852 853 EEO_CASE(EEOP_JUMP_IF_NULL) 854 { 855 /* Transfer control if current result is null */ 856 if (*op->resnull) 857 EEO_JUMP(op->d.jump.jumpdone); 858 859 EEO_NEXT(); 860 } 861 862 EEO_CASE(EEOP_JUMP_IF_NOT_NULL) 863 { 864 /* Transfer control if current result is non-null */ 865 if (!*op->resnull) 866 EEO_JUMP(op->d.jump.jumpdone); 867 868 EEO_NEXT(); 869 } 870 871 EEO_CASE(EEOP_JUMP_IF_NOT_TRUE) 872 { 873 /* Transfer control if current result is null or false */ 874 if (*op->resnull || !DatumGetBool(*op->resvalue)) 875 EEO_JUMP(op->d.jump.jumpdone); 876 877 EEO_NEXT(); 878 } 879 880 EEO_CASE(EEOP_NULLTEST_ISNULL) 881 { 882 *op->resvalue = BoolGetDatum(*op->resnull); 883 *op->resnull = false; 884 885 EEO_NEXT(); 886 } 887 888 EEO_CASE(EEOP_NULLTEST_ISNOTNULL) 889 { 890 *op->resvalue = BoolGetDatum(!*op->resnull); 891 *op->resnull = false; 892 893 EEO_NEXT(); 894 } 895 896 EEO_CASE(EEOP_NULLTEST_ROWISNULL) 897 { 898 /* out of line implementation: too large */ 899 ExecEvalRowNull(state, op, econtext); 900 901 EEO_NEXT(); 902 } 903 904 EEO_CASE(EEOP_NULLTEST_ROWISNOTNULL) 905 { 906 /* out of line implementation: too large */ 907 ExecEvalRowNotNull(state, op, econtext); 908 909 EEO_NEXT(); 910 } 911 912 /* BooleanTest implementations for all booltesttypes */ 913 914 EEO_CASE(EEOP_BOOLTEST_IS_TRUE) 915 { 916 if (*op->resnull) 917 { 918 *op->resvalue = BoolGetDatum(false); 919 *op->resnull = false; 920 } 921 /* else, input value is the correct output as well */ 922 923 EEO_NEXT(); 924 } 925 926 EEO_CASE(EEOP_BOOLTEST_IS_NOT_TRUE) 927 { 928 if (*op->resnull) 929 { 930 *op->resvalue = BoolGetDatum(true); 931 *op->resnull = false; 932 } 933 else 934 *op->resvalue = BoolGetDatum(!DatumGetBool(*op->resvalue)); 935 936 EEO_NEXT(); 937 } 938 939 EEO_CASE(EEOP_BOOLTEST_IS_FALSE) 940 { 941 if (*op->resnull) 942 { 943 *op->resvalue = BoolGetDatum(false); 944 *op->resnull = false; 945 } 946 else 947 *op->resvalue = BoolGetDatum(!DatumGetBool(*op->resvalue)); 948 949 EEO_NEXT(); 950 } 951 952 EEO_CASE(EEOP_BOOLTEST_IS_NOT_FALSE) 953 { 954 if (*op->resnull) 955 { 956 *op->resvalue = BoolGetDatum(true); 957 *op->resnull = false; 958 } 959 /* else, input value is the correct output as well */ 960 961 EEO_NEXT(); 962 } 963 964 EEO_CASE(EEOP_PARAM_EXEC) 965 { 966 /* out of line implementation: too large */ 967 ExecEvalParamExec(state, op, econtext); 968 969 EEO_NEXT(); 970 } 971 972 EEO_CASE(EEOP_PARAM_EXTERN) 973 { 974 /* out of line implementation: too large */ 975 ExecEvalParamExtern(state, op, econtext); 976 EEO_NEXT(); 977 } 978 979 EEO_CASE(EEOP_PARAM_CALLBACK) 980 { 981 /* allow an extension module to supply a PARAM_EXTERN value */ 982 op->d.cparam.paramfunc(state, op, econtext); 983 EEO_NEXT(); 984 } 985 986 EEO_CASE(EEOP_CASE_TESTVAL) 987 { 988 /* 989 * Normally upper parts of the expression tree have setup the 990 * values to be returned here, but some parts of the system 991 * currently misuse {caseValue,domainValue}_{datum,isNull} to set 992 * run-time data. So if no values have been set-up, use 993 * ExprContext's. This isn't pretty, but also not *that* ugly, 994 * and this is unlikely to be performance sensitive enough to 995 * worry about an extra branch. 996 */ 997 if (op->d.casetest.value) 998 { 999 *op->resvalue = *op->d.casetest.value; 1000 *op->resnull = *op->d.casetest.isnull; 1001 } 1002 else 1003 { 1004 *op->resvalue = econtext->caseValue_datum; 1005 *op->resnull = econtext->caseValue_isNull; 1006 } 1007 1008 EEO_NEXT(); 1009 } 1010 1011 EEO_CASE(EEOP_DOMAIN_TESTVAL) 1012 { 1013 /* 1014 * See EEOP_CASE_TESTVAL comment. 1015 */ 1016 if (op->d.casetest.value) 1017 { 1018 *op->resvalue = *op->d.casetest.value; 1019 *op->resnull = *op->d.casetest.isnull; 1020 } 1021 else 1022 { 1023 *op->resvalue = econtext->domainValue_datum; 1024 *op->resnull = econtext->domainValue_isNull; 1025 } 1026 1027 EEO_NEXT(); 1028 } 1029 1030 EEO_CASE(EEOP_MAKE_READONLY) 1031 { 1032 /* 1033 * Force a varlena value that might be read multiple times to R/O 1034 */ 1035 if (!*op->d.make_readonly.isnull) 1036 *op->resvalue = 1037 MakeExpandedObjectReadOnlyInternal(*op->d.make_readonly.value); 1038 *op->resnull = *op->d.make_readonly.isnull; 1039 1040 EEO_NEXT(); 1041 } 1042 1043 EEO_CASE(EEOP_IOCOERCE) 1044 { 1045 /* 1046 * Evaluate a CoerceViaIO node. This can be quite a hot path, so 1047 * inline as much work as possible. The source value is in our 1048 * result variable. 1049 */ 1050 char *str; 1051 1052 /* call output function (similar to OutputFunctionCall) */ 1053 if (*op->resnull) 1054 { 1055 /* output functions are not called on nulls */ 1056 str = NULL; 1057 } 1058 else 1059 { 1060 FunctionCallInfo fcinfo_out; 1061 1062 fcinfo_out = op->d.iocoerce.fcinfo_data_out; 1063 fcinfo_out->args[0].value = *op->resvalue; 1064 fcinfo_out->args[0].isnull = false; 1065 1066 fcinfo_out->isnull = false; 1067 str = DatumGetCString(FunctionCallInvoke(fcinfo_out)); 1068 1069 /* OutputFunctionCall assumes result isn't null */ 1070 Assert(!fcinfo_out->isnull); 1071 } 1072 1073 /* call input function (similar to InputFunctionCall) */ 1074 if (!op->d.iocoerce.finfo_in->fn_strict || str != NULL) 1075 { 1076 FunctionCallInfo fcinfo_in; 1077 Datum d; 1078 1079 fcinfo_in = op->d.iocoerce.fcinfo_data_in; 1080 fcinfo_in->args[0].value = PointerGetDatum(str); 1081 fcinfo_in->args[0].isnull = *op->resnull; 1082 /* second and third arguments are already set up */ 1083 1084 fcinfo_in->isnull = false; 1085 d = FunctionCallInvoke(fcinfo_in); 1086 *op->resvalue = d; 1087 1088 /* Should get null result if and only if str is NULL */ 1089 if (str == NULL) 1090 { 1091 Assert(*op->resnull); 1092 Assert(fcinfo_in->isnull); 1093 } 1094 else 1095 { 1096 Assert(!*op->resnull); 1097 Assert(!fcinfo_in->isnull); 1098 } 1099 } 1100 1101 EEO_NEXT(); 1102 } 1103 1104 EEO_CASE(EEOP_DISTINCT) 1105 { 1106 /* 1107 * IS DISTINCT FROM must evaluate arguments (already done into 1108 * fcinfo->args) to determine whether they are NULL; if either is 1109 * NULL then the result is determined. If neither is NULL, then 1110 * proceed to evaluate the comparison function, which is just the 1111 * type's standard equality operator. We need not care whether 1112 * that function is strict. Because the handling of nulls is 1113 * different, we can't just reuse EEOP_FUNCEXPR. 1114 */ 1115 FunctionCallInfo fcinfo = op->d.func.fcinfo_data; 1116 1117 /* check function arguments for NULLness */ 1118 if (fcinfo->args[0].isnull && fcinfo->args[1].isnull) 1119 { 1120 /* Both NULL? Then is not distinct... */ 1121 *op->resvalue = BoolGetDatum(false); 1122 *op->resnull = false; 1123 } 1124 else if (fcinfo->args[0].isnull || fcinfo->args[1].isnull) 1125 { 1126 /* Only one is NULL? Then is distinct... */ 1127 *op->resvalue = BoolGetDatum(true); 1128 *op->resnull = false; 1129 } 1130 else 1131 { 1132 /* Neither null, so apply the equality function */ 1133 Datum eqresult; 1134 1135 fcinfo->isnull = false; 1136 eqresult = op->d.func.fn_addr(fcinfo); 1137 /* Must invert result of "="; safe to do even if null */ 1138 *op->resvalue = BoolGetDatum(!DatumGetBool(eqresult)); 1139 *op->resnull = fcinfo->isnull; 1140 } 1141 1142 EEO_NEXT(); 1143 } 1144 1145 /* see EEOP_DISTINCT for comments, this is just inverted */ 1146 EEO_CASE(EEOP_NOT_DISTINCT) 1147 { 1148 FunctionCallInfo fcinfo = op->d.func.fcinfo_data; 1149 1150 if (fcinfo->args[0].isnull && fcinfo->args[1].isnull) 1151 { 1152 *op->resvalue = BoolGetDatum(true); 1153 *op->resnull = false; 1154 } 1155 else if (fcinfo->args[0].isnull || fcinfo->args[1].isnull) 1156 { 1157 *op->resvalue = BoolGetDatum(false); 1158 *op->resnull = false; 1159 } 1160 else 1161 { 1162 Datum eqresult; 1163 1164 fcinfo->isnull = false; 1165 eqresult = op->d.func.fn_addr(fcinfo); 1166 *op->resvalue = eqresult; 1167 *op->resnull = fcinfo->isnull; 1168 } 1169 1170 EEO_NEXT(); 1171 } 1172 1173 EEO_CASE(EEOP_NULLIF) 1174 { 1175 /* 1176 * The arguments are already evaluated into fcinfo->args. 1177 */ 1178 FunctionCallInfo fcinfo = op->d.func.fcinfo_data; 1179 1180 /* if either argument is NULL they can't be equal */ 1181 if (!fcinfo->args[0].isnull && !fcinfo->args[1].isnull) 1182 { 1183 Datum result; 1184 1185 fcinfo->isnull = false; 1186 result = op->d.func.fn_addr(fcinfo); 1187 1188 /* if the arguments are equal return null */ 1189 if (!fcinfo->isnull && DatumGetBool(result)) 1190 { 1191 *op->resvalue = (Datum) 0; 1192 *op->resnull = true; 1193 1194 EEO_NEXT(); 1195 } 1196 } 1197 1198 /* Arguments aren't equal, so return the first one */ 1199 *op->resvalue = fcinfo->args[0].value; 1200 *op->resnull = fcinfo->args[0].isnull; 1201 1202 EEO_NEXT(); 1203 } 1204 1205 EEO_CASE(EEOP_SQLVALUEFUNCTION) 1206 { 1207 /* 1208 * Doesn't seem worthwhile to have an inline implementation 1209 * efficiency-wise. 1210 */ 1211 ExecEvalSQLValueFunction(state, op); 1212 1213 EEO_NEXT(); 1214 } 1215 1216 EEO_CASE(EEOP_CURRENTOFEXPR) 1217 { 1218 /* error invocation uses space, and shouldn't ever occur */ 1219 ExecEvalCurrentOfExpr(state, op); 1220 1221 EEO_NEXT(); 1222 } 1223 1224 EEO_CASE(EEOP_NEXTVALUEEXPR) 1225 { 1226 /* 1227 * Doesn't seem worthwhile to have an inline implementation 1228 * efficiency-wise. 1229 */ 1230 ExecEvalNextValueExpr(state, op); 1231 1232 EEO_NEXT(); 1233 } 1234 1235 EEO_CASE(EEOP_ARRAYEXPR) 1236 { 1237 /* too complex for an inline implementation */ 1238 ExecEvalArrayExpr(state, op); 1239 1240 EEO_NEXT(); 1241 } 1242 1243 EEO_CASE(EEOP_ARRAYCOERCE) 1244 { 1245 /* too complex for an inline implementation */ 1246 ExecEvalArrayCoerce(state, op, econtext); 1247 1248 EEO_NEXT(); 1249 } 1250 1251 EEO_CASE(EEOP_ROW) 1252 { 1253 /* too complex for an inline implementation */ 1254 ExecEvalRow(state, op); 1255 1256 EEO_NEXT(); 1257 } 1258 1259 EEO_CASE(EEOP_ROWCOMPARE_STEP) 1260 { 1261 FunctionCallInfo fcinfo = op->d.rowcompare_step.fcinfo_data; 1262 Datum d; 1263 1264 /* force NULL result if strict fn and NULL input */ 1265 if (op->d.rowcompare_step.finfo->fn_strict && 1266 (fcinfo->args[0].isnull || fcinfo->args[1].isnull)) 1267 { 1268 *op->resnull = true; 1269 EEO_JUMP(op->d.rowcompare_step.jumpnull); 1270 } 1271 1272 /* Apply comparison function */ 1273 fcinfo->isnull = false; 1274 d = op->d.rowcompare_step.fn_addr(fcinfo); 1275 *op->resvalue = d; 1276 1277 /* force NULL result if NULL function result */ 1278 if (fcinfo->isnull) 1279 { 1280 *op->resnull = true; 1281 EEO_JUMP(op->d.rowcompare_step.jumpnull); 1282 } 1283 *op->resnull = false; 1284 1285 /* If unequal, no need to compare remaining columns */ 1286 if (DatumGetInt32(*op->resvalue) != 0) 1287 { 1288 EEO_JUMP(op->d.rowcompare_step.jumpdone); 1289 } 1290 1291 EEO_NEXT(); 1292 } 1293 1294 EEO_CASE(EEOP_ROWCOMPARE_FINAL) 1295 { 1296 int32 cmpresult = DatumGetInt32(*op->resvalue); 1297 RowCompareType rctype = op->d.rowcompare_final.rctype; 1298 1299 *op->resnull = false; 1300 switch (rctype) 1301 { 1302 /* EQ and NE cases aren't allowed here */ 1303 case ROWCOMPARE_LT: 1304 *op->resvalue = BoolGetDatum(cmpresult < 0); 1305 break; 1306 case ROWCOMPARE_LE: 1307 *op->resvalue = BoolGetDatum(cmpresult <= 0); 1308 break; 1309 case ROWCOMPARE_GE: 1310 *op->resvalue = BoolGetDatum(cmpresult >= 0); 1311 break; 1312 case ROWCOMPARE_GT: 1313 *op->resvalue = BoolGetDatum(cmpresult > 0); 1314 break; 1315 default: 1316 Assert(false); 1317 break; 1318 } 1319 1320 EEO_NEXT(); 1321 } 1322 1323 EEO_CASE(EEOP_MINMAX) 1324 { 1325 /* too complex for an inline implementation */ 1326 ExecEvalMinMax(state, op); 1327 1328 EEO_NEXT(); 1329 } 1330 1331 EEO_CASE(EEOP_FIELDSELECT) 1332 { 1333 /* too complex for an inline implementation */ 1334 ExecEvalFieldSelect(state, op, econtext); 1335 1336 EEO_NEXT(); 1337 } 1338 1339 EEO_CASE(EEOP_FIELDSTORE_DEFORM) 1340 { 1341 /* too complex for an inline implementation */ 1342 ExecEvalFieldStoreDeForm(state, op, econtext); 1343 1344 EEO_NEXT(); 1345 } 1346 1347 EEO_CASE(EEOP_FIELDSTORE_FORM) 1348 { 1349 /* too complex for an inline implementation */ 1350 ExecEvalFieldStoreForm(state, op, econtext); 1351 1352 EEO_NEXT(); 1353 } 1354 1355 EEO_CASE(EEOP_SBSREF_SUBSCRIPT) 1356 { 1357 /* Process an array subscript */ 1358 1359 /* too complex for an inline implementation */ 1360 if (ExecEvalSubscriptingRef(state, op)) 1361 { 1362 EEO_NEXT(); 1363 } 1364 else 1365 { 1366 /* Subscript is null, short-circuit SubscriptingRef to NULL */ 1367 EEO_JUMP(op->d.sbsref_subscript.jumpdone); 1368 } 1369 } 1370 1371 EEO_CASE(EEOP_SBSREF_OLD) 1372 { 1373 /* 1374 * Fetch the old value in an sbsref assignment, in case it's 1375 * referenced (via a CaseTestExpr) inside the assignment 1376 * expression. 1377 */ 1378 1379 /* too complex for an inline implementation */ 1380 ExecEvalSubscriptingRefOld(state, op); 1381 1382 EEO_NEXT(); 1383 } 1384 1385 /* 1386 * Perform SubscriptingRef assignment 1387 */ 1388 EEO_CASE(EEOP_SBSREF_ASSIGN) 1389 { 1390 /* too complex for an inline implementation */ 1391 ExecEvalSubscriptingRefAssign(state, op); 1392 1393 EEO_NEXT(); 1394 } 1395 1396 /* 1397 * Fetch subset of an array. 1398 */ 1399 EEO_CASE(EEOP_SBSREF_FETCH) 1400 { 1401 /* too complex for an inline implementation */ 1402 ExecEvalSubscriptingRefFetch(state, op); 1403 1404 EEO_NEXT(); 1405 } 1406 1407 EEO_CASE(EEOP_CONVERT_ROWTYPE) 1408 { 1409 /* too complex for an inline implementation */ 1410 ExecEvalConvertRowtype(state, op, econtext); 1411 1412 EEO_NEXT(); 1413 } 1414 1415 EEO_CASE(EEOP_SCALARARRAYOP) 1416 { 1417 /* too complex for an inline implementation */ 1418 ExecEvalScalarArrayOp(state, op); 1419 1420 EEO_NEXT(); 1421 } 1422 1423 EEO_CASE(EEOP_DOMAIN_NOTNULL) 1424 { 1425 /* too complex for an inline implementation */ 1426 ExecEvalConstraintNotNull(state, op); 1427 1428 EEO_NEXT(); 1429 } 1430 1431 EEO_CASE(EEOP_DOMAIN_CHECK) 1432 { 1433 /* too complex for an inline implementation */ 1434 ExecEvalConstraintCheck(state, op); 1435 1436 EEO_NEXT(); 1437 } 1438 1439 EEO_CASE(EEOP_XMLEXPR) 1440 { 1441 /* too complex for an inline implementation */ 1442 ExecEvalXmlExpr(state, op); 1443 1444 EEO_NEXT(); 1445 } 1446 1447 EEO_CASE(EEOP_AGGREF) 1448 { 1449 /* 1450 * Returns a Datum whose value is the precomputed aggregate value 1451 * found in the given expression context. 1452 */ 1453 AggrefExprState *aggref = op->d.aggref.astate; 1454 1455 Assert(econtext->ecxt_aggvalues != NULL); 1456 1457 *op->resvalue = econtext->ecxt_aggvalues[aggref->aggno]; 1458 *op->resnull = econtext->ecxt_aggnulls[aggref->aggno]; 1459 1460 EEO_NEXT(); 1461 } 1462 1463 EEO_CASE(EEOP_GROUPING_FUNC) 1464 { 1465 /* too complex/uncommon for an inline implementation */ 1466 ExecEvalGroupingFunc(state, op); 1467 1468 EEO_NEXT(); 1469 } 1470 1471 EEO_CASE(EEOP_WINDOW_FUNC) 1472 { 1473 /* 1474 * Like Aggref, just return a precomputed value from the econtext. 1475 */ 1476 WindowFuncExprState *wfunc = op->d.window_func.wfstate; 1477 1478 Assert(econtext->ecxt_aggvalues != NULL); 1479 1480 *op->resvalue = econtext->ecxt_aggvalues[wfunc->wfuncno]; 1481 *op->resnull = econtext->ecxt_aggnulls[wfunc->wfuncno]; 1482 1483 EEO_NEXT(); 1484 } 1485 1486 EEO_CASE(EEOP_SUBPLAN) 1487 { 1488 /* too complex for an inline implementation */ 1489 ExecEvalSubPlan(state, op, econtext); 1490 1491 EEO_NEXT(); 1492 } 1493 1494 EEO_CASE(EEOP_ALTERNATIVE_SUBPLAN) 1495 { 1496 /* too complex for an inline implementation */ 1497 ExecEvalAlternativeSubPlan(state, op, econtext); 1498 1499 EEO_NEXT(); 1500 } 1501 1502 /* evaluate a strict aggregate deserialization function */ 1503 EEO_CASE(EEOP_AGG_STRICT_DESERIALIZE) 1504 { 1505 /* Don't call a strict deserialization function with NULL input */ 1506 if (op->d.agg_deserialize.fcinfo_data->args[0].isnull) 1507 EEO_JUMP(op->d.agg_deserialize.jumpnull); 1508 1509 /* fallthrough */ 1510 } 1511 1512 /* evaluate aggregate deserialization function (non-strict portion) */ 1513 EEO_CASE(EEOP_AGG_DESERIALIZE) 1514 { 1515 FunctionCallInfo fcinfo = op->d.agg_deserialize.fcinfo_data; 1516 AggState *aggstate = op->d.agg_deserialize.aggstate; 1517 MemoryContext oldContext; 1518 1519 /* 1520 * We run the deserialization functions in per-input-tuple memory 1521 * context. 1522 */ 1523 oldContext = MemoryContextSwitchTo(aggstate->tmpcontext->ecxt_per_tuple_memory); 1524 fcinfo->isnull = false; 1525 *op->resvalue = FunctionCallInvoke(fcinfo); 1526 *op->resnull = fcinfo->isnull; 1527 MemoryContextSwitchTo(oldContext); 1528 1529 EEO_NEXT(); 1530 } 1531 1532 /* 1533 * Check that a strict aggregate transition / combination function's 1534 * input is not NULL. 1535 */ 1536 EEO_CASE(EEOP_AGG_STRICT_INPUT_CHECK_NULLS) 1537 { 1538 int argno; 1539 bool *nulls = op->d.agg_strict_input_check.nulls; 1540 int nargs = op->d.agg_strict_input_check.nargs; 1541 1542 for (argno = 0; argno < nargs; argno++) 1543 { 1544 if (nulls[argno]) 1545 EEO_JUMP(op->d.agg_strict_input_check.jumpnull); 1546 } 1547 EEO_NEXT(); 1548 } 1549 1550 EEO_CASE(EEOP_AGG_STRICT_INPUT_CHECK_ARGS) 1551 { 1552 int argno; 1553 NullableDatum *args = op->d.agg_strict_input_check.args; 1554 int nargs = op->d.agg_strict_input_check.nargs; 1555 1556 for (argno = 0; argno < nargs; argno++) 1557 { 1558 if (args[argno].isnull) 1559 EEO_JUMP(op->d.agg_strict_input_check.jumpnull); 1560 } 1561 EEO_NEXT(); 1562 } 1563 1564 /* 1565 * Initialize an aggregate's first value if necessary. 1566 */ 1567 EEO_CASE(EEOP_AGG_INIT_TRANS) 1568 { 1569 AggState *aggstate; 1570 AggStatePerGroup pergroup; 1571 1572 aggstate = op->d.agg_init_trans.aggstate; 1573 pergroup = &aggstate->all_pergroups 1574 [op->d.agg_init_trans.setoff] 1575 [op->d.agg_init_trans.transno]; 1576 1577 /* If transValue has not yet been initialized, do so now. */ 1578 if (pergroup->noTransValue) 1579 { 1580 AggStatePerTrans pertrans = op->d.agg_init_trans.pertrans; 1581 1582 aggstate->curaggcontext = op->d.agg_init_trans.aggcontext; 1583 aggstate->current_set = op->d.agg_init_trans.setno; 1584 1585 ExecAggInitGroup(aggstate, pertrans, pergroup); 1586 1587 /* copied trans value from input, done this round */ 1588 EEO_JUMP(op->d.agg_init_trans.jumpnull); 1589 } 1590 1591 EEO_NEXT(); 1592 } 1593 1594 /* check that a strict aggregate's input isn't NULL */ 1595 EEO_CASE(EEOP_AGG_STRICT_TRANS_CHECK) 1596 { 1597 AggState *aggstate; 1598 AggStatePerGroup pergroup; 1599 1600 aggstate = op->d.agg_strict_trans_check.aggstate; 1601 pergroup = &aggstate->all_pergroups 1602 [op->d.agg_strict_trans_check.setoff] 1603 [op->d.agg_strict_trans_check.transno]; 1604 1605 if (unlikely(pergroup->transValueIsNull)) 1606 EEO_JUMP(op->d.agg_strict_trans_check.jumpnull); 1607 1608 EEO_NEXT(); 1609 } 1610 1611 /* 1612 * Evaluate aggregate transition / combine function that has a 1613 * by-value transition type. That's a separate case from the 1614 * by-reference implementation because it's a bit simpler. 1615 */ 1616 EEO_CASE(EEOP_AGG_PLAIN_TRANS_BYVAL) 1617 { 1618 AggState *aggstate; 1619 AggStatePerTrans pertrans; 1620 AggStatePerGroup pergroup; 1621 FunctionCallInfo fcinfo; 1622 MemoryContext oldContext; 1623 Datum newVal; 1624 1625 aggstate = op->d.agg_trans.aggstate; 1626 pertrans = op->d.agg_trans.pertrans; 1627 1628 pergroup = &aggstate->all_pergroups 1629 [op->d.agg_trans.setoff] 1630 [op->d.agg_trans.transno]; 1631 1632 Assert(pertrans->transtypeByVal); 1633 1634 fcinfo = pertrans->transfn_fcinfo; 1635 1636 /* cf. select_current_set() */ 1637 aggstate->curaggcontext = op->d.agg_trans.aggcontext; 1638 aggstate->current_set = op->d.agg_trans.setno; 1639 1640 /* set up aggstate->curpertrans for AggGetAggref() */ 1641 aggstate->curpertrans = pertrans; 1642 1643 /* invoke transition function in per-tuple context */ 1644 oldContext = MemoryContextSwitchTo(aggstate->tmpcontext->ecxt_per_tuple_memory); 1645 1646 fcinfo->args[0].value = pergroup->transValue; 1647 fcinfo->args[0].isnull = pergroup->transValueIsNull; 1648 fcinfo->isnull = false; /* just in case transfn doesn't set it */ 1649 1650 newVal = FunctionCallInvoke(fcinfo); 1651 1652 pergroup->transValue = newVal; 1653 pergroup->transValueIsNull = fcinfo->isnull; 1654 1655 MemoryContextSwitchTo(oldContext); 1656 1657 EEO_NEXT(); 1658 } 1659 1660 /* 1661 * Evaluate aggregate transition / combine function that has a 1662 * by-reference transition type. 1663 * 1664 * Could optimize a bit further by splitting off by-reference 1665 * fixed-length types, but currently that doesn't seem worth it. 1666 */ 1667 EEO_CASE(EEOP_AGG_PLAIN_TRANS) 1668 { 1669 AggState *aggstate; 1670 AggStatePerTrans pertrans; 1671 AggStatePerGroup pergroup; 1672 FunctionCallInfo fcinfo; 1673 MemoryContext oldContext; 1674 Datum newVal; 1675 1676 aggstate = op->d.agg_trans.aggstate; 1677 pertrans = op->d.agg_trans.pertrans; 1678 1679 pergroup = &aggstate->all_pergroups 1680 [op->d.agg_trans.setoff] 1681 [op->d.agg_trans.transno]; 1682 1683 Assert(!pertrans->transtypeByVal); 1684 1685 fcinfo = pertrans->transfn_fcinfo; 1686 1687 /* cf. select_current_set() */ 1688 aggstate->curaggcontext = op->d.agg_trans.aggcontext; 1689 aggstate->current_set = op->d.agg_trans.setno; 1690 1691 /* set up aggstate->curpertrans for AggGetAggref() */ 1692 aggstate->curpertrans = pertrans; 1693 1694 /* invoke transition function in per-tuple context */ 1695 oldContext = MemoryContextSwitchTo(aggstate->tmpcontext->ecxt_per_tuple_memory); 1696 1697 fcinfo->args[0].value = pergroup->transValue; 1698 fcinfo->args[0].isnull = pergroup->transValueIsNull; 1699 fcinfo->isnull = false; /* just in case transfn doesn't set it */ 1700 1701 newVal = FunctionCallInvoke(fcinfo); 1702 1703 /* 1704 * For pass-by-ref datatype, must copy the new value into 1705 * aggcontext and free the prior transValue. But if transfn 1706 * returned a pointer to its first input, we don't need to do 1707 * anything. Also, if transfn returned a pointer to a R/W 1708 * expanded object that is already a child of the aggcontext, 1709 * assume we can adopt that value without copying it. 1710 * 1711 * It's safe to compare newVal with pergroup->transValue without 1712 * regard for either being NULL, because ExecAggTransReparent() 1713 * takes care to set transValue to 0 when NULL. Otherwise we could 1714 * end up accidentally not reparenting, when the transValue has 1715 * the same numerical value as newValue, despite being NULL. This 1716 * is a somewhat hot path, making it undesirable to instead solve 1717 * this with another branch for the common case of the transition 1718 * function returning its (modified) input argument. 1719 */ 1720 if (DatumGetPointer(newVal) != DatumGetPointer(pergroup->transValue)) 1721 newVal = ExecAggTransReparent(aggstate, pertrans, 1722 newVal, fcinfo->isnull, 1723 pergroup->transValue, 1724 pergroup->transValueIsNull); 1725 1726 pergroup->transValue = newVal; 1727 pergroup->transValueIsNull = fcinfo->isnull; 1728 1729 MemoryContextSwitchTo(oldContext); 1730 1731 EEO_NEXT(); 1732 } 1733 1734 /* process single-column ordered aggregate datum */ 1735 EEO_CASE(EEOP_AGG_ORDERED_TRANS_DATUM) 1736 { 1737 /* too complex for an inline implementation */ 1738 ExecEvalAggOrderedTransDatum(state, op, econtext); 1739 1740 EEO_NEXT(); 1741 } 1742 1743 /* process multi-column ordered aggregate tuple */ 1744 EEO_CASE(EEOP_AGG_ORDERED_TRANS_TUPLE) 1745 { 1746 /* too complex for an inline implementation */ 1747 ExecEvalAggOrderedTransTuple(state, op, econtext); 1748 1749 EEO_NEXT(); 1750 } 1751 1752 EEO_CASE(EEOP_LAST) 1753 { 1754 /* unreachable */ 1755 Assert(false); 1756 goto out; 1757 } 1758 } 1759 1760 out: 1761 *isnull = state->resnull; 1762 return state->resvalue; 1763 } 1764 1765 /* 1766 * Expression evaluation callback that performs extra checks before executing 1767 * the expression. Declared extern so other methods of execution can use it 1768 * too. 1769 */ 1770 Datum 1771 ExecInterpExprStillValid(ExprState *state, ExprContext *econtext, bool *isNull) 1772 { 1773 /* 1774 * First time through, check whether attribute matches Var. Might not be 1775 * ok anymore, due to schema changes. 1776 */ 1777 CheckExprStillValid(state, econtext); 1778 1779 /* skip the check during further executions */ 1780 state->evalfunc = (ExprStateEvalFunc) state->evalfunc_private; 1781 1782 /* and actually execute */ 1783 return state->evalfunc(state, econtext, isNull); 1784 } 1785 1786 /* 1787 * Check that an expression is still valid in the face of potential schema 1788 * changes since the plan has been created. 1789 */ 1790 void 1791 CheckExprStillValid(ExprState *state, ExprContext *econtext) 1792 { 1793 int i = 0; 1794 TupleTableSlot *innerslot; 1795 TupleTableSlot *outerslot; 1796 TupleTableSlot *scanslot; 1797 1798 innerslot = econtext->ecxt_innertuple; 1799 outerslot = econtext->ecxt_outertuple; 1800 scanslot = econtext->ecxt_scantuple; 1801 1802 for (i = 0; i < state->steps_len; i++) 1803 { 1804 ExprEvalStep *op = &state->steps[i]; 1805 1806 switch (ExecEvalStepOp(state, op)) 1807 { 1808 case EEOP_INNER_VAR: 1809 { 1810 int attnum = op->d.var.attnum; 1811 1812 CheckVarSlotCompatibility(innerslot, attnum + 1, op->d.var.vartype); 1813 break; 1814 } 1815 1816 case EEOP_OUTER_VAR: 1817 { 1818 int attnum = op->d.var.attnum; 1819 1820 CheckVarSlotCompatibility(outerslot, attnum + 1, op->d.var.vartype); 1821 break; 1822 } 1823 1824 case EEOP_SCAN_VAR: 1825 { 1826 int attnum = op->d.var.attnum; 1827 1828 CheckVarSlotCompatibility(scanslot, attnum + 1, op->d.var.vartype); 1829 break; 1830 } 1831 default: 1832 break; 1833 } 1834 } 1835 } 1836 1837 /* 1838 * Check whether a user attribute in a slot can be referenced by a Var 1839 * expression. This should succeed unless there have been schema changes 1840 * since the expression tree has been created. 1841 */ 1842 static void 1843 CheckVarSlotCompatibility(TupleTableSlot *slot, int attnum, Oid vartype) 1844 { 1845 /* 1846 * What we have to check for here is the possibility of an attribute 1847 * having been dropped or changed in type since the plan tree was created. 1848 * Ideally the plan will get invalidated and not re-used, but just in 1849 * case, we keep these defenses. Fortunately it's sufficient to check 1850 * once on the first time through. 1851 * 1852 * Note: ideally we'd check typmod as well as typid, but that seems 1853 * impractical at the moment: in many cases the tupdesc will have been 1854 * generated by ExecTypeFromTL(), and that can't guarantee to generate an 1855 * accurate typmod in all cases, because some expression node types don't 1856 * carry typmod. Fortunately, for precisely that reason, there should be 1857 * no places with a critical dependency on the typmod of a value. 1858 * 1859 * System attributes don't require checking since their types never 1860 * change. 1861 */ 1862 if (attnum > 0) 1863 { 1864 TupleDesc slot_tupdesc = slot->tts_tupleDescriptor; 1865 Form_pg_attribute attr; 1866 1867 if (attnum > slot_tupdesc->natts) /* should never happen */ 1868 elog(ERROR, "attribute number %d exceeds number of columns %d", 1869 attnum, slot_tupdesc->natts); 1870 1871 attr = TupleDescAttr(slot_tupdesc, attnum - 1); 1872 1873 if (attr->attisdropped) 1874 ereport(ERROR, 1875 (errcode(ERRCODE_UNDEFINED_COLUMN), 1876 errmsg("attribute %d of type %s has been dropped", 1877 attnum, format_type_be(slot_tupdesc->tdtypeid)))); 1878 1879 if (vartype != attr->atttypid) 1880 ereport(ERROR, 1881 (errcode(ERRCODE_DATATYPE_MISMATCH), 1882 errmsg("attribute %d of type %s has wrong type", 1883 attnum, format_type_be(slot_tupdesc->tdtypeid)), 1884 errdetail("Table has type %s, but query expects %s.", 1885 format_type_be(attr->atttypid), 1886 format_type_be(vartype)))); 1887 } 1888 } 1889 1890 /* 1891 * Verify that the slot is compatible with a EEOP_*_FETCHSOME operation. 1892 */ 1893 static void 1894 CheckOpSlotCompatibility(ExprEvalStep *op, TupleTableSlot *slot) 1895 { 1896 #ifdef USE_ASSERT_CHECKING 1897 /* there's nothing to check */ 1898 if (!op->d.fetch.fixed) 1899 return; 1900 1901 /* 1902 * Should probably fixed at some point, but for now it's easier to allow 1903 * buffer and heap tuples to be used interchangeably. 1904 */ 1905 if (slot->tts_ops == &TTSOpsBufferHeapTuple && 1906 op->d.fetch.kind == &TTSOpsHeapTuple) 1907 return; 1908 if (slot->tts_ops == &TTSOpsHeapTuple && 1909 op->d.fetch.kind == &TTSOpsBufferHeapTuple) 1910 return; 1911 1912 /* 1913 * At the moment we consider it OK if a virtual slot is used instead of a 1914 * specific type of slot, as a virtual slot never needs to be deformed. 1915 */ 1916 if (slot->tts_ops == &TTSOpsVirtual) 1917 return; 1918 1919 Assert(op->d.fetch.kind == slot->tts_ops); 1920 #endif 1921 } 1922 1923 /* 1924 * get_cached_rowtype: utility function to lookup a rowtype tupdesc 1925 * 1926 * type_id, typmod: identity of the rowtype 1927 * rowcache: space for caching identity info 1928 * (rowcache->cacheptr must be initialized to NULL) 1929 * changed: if not NULL, *changed is set to true on any update 1930 * 1931 * The returned TupleDesc is not guaranteed pinned; caller must pin it 1932 * to use it across any operation that might incur cache invalidation. 1933 * (The TupleDesc is always refcounted, so just use IncrTupleDescRefCount.) 1934 * 1935 * NOTE: because composite types can change contents, we must be prepared 1936 * to re-do this during any node execution; cannot call just once during 1937 * expression initialization. 1938 */ 1939 static TupleDesc 1940 get_cached_rowtype(Oid type_id, int32 typmod, 1941 ExprEvalRowtypeCache *rowcache, 1942 bool *changed) 1943 { 1944 if (type_id != RECORDOID) 1945 { 1946 /* 1947 * It's a named composite type, so use the regular typcache. Do a 1948 * lookup first time through, or if the composite type changed. Note: 1949 * "tupdesc_id == 0" may look redundant, but it protects against the 1950 * admittedly-theoretical possibility that type_id was RECORDOID the 1951 * last time through, so that the cacheptr isn't TypeCacheEntry *. 1952 */ 1953 TypeCacheEntry *typentry = (TypeCacheEntry *) rowcache->cacheptr; 1954 1955 if (unlikely(typentry == NULL || 1956 rowcache->tupdesc_id == 0 || 1957 typentry->tupDesc_identifier != rowcache->tupdesc_id)) 1958 { 1959 typentry = lookup_type_cache(type_id, TYPECACHE_TUPDESC); 1960 if (typentry->tupDesc == NULL) 1961 ereport(ERROR, 1962 (errcode(ERRCODE_WRONG_OBJECT_TYPE), 1963 errmsg("type %s is not composite", 1964 format_type_be(type_id)))); 1965 rowcache->cacheptr = (void *) typentry; 1966 rowcache->tupdesc_id = typentry->tupDesc_identifier; 1967 if (changed) 1968 *changed = true; 1969 } 1970 return typentry->tupDesc; 1971 } 1972 else 1973 { 1974 /* 1975 * A RECORD type, once registered, doesn't change for the life of the 1976 * backend. So we don't need a typcache entry as such, which is good 1977 * because there isn't one. It's possible that the caller is asking 1978 * about a different type than before, though. 1979 */ 1980 TupleDesc tupDesc = (TupleDesc) rowcache->cacheptr; 1981 1982 if (unlikely(tupDesc == NULL || 1983 rowcache->tupdesc_id != 0 || 1984 type_id != tupDesc->tdtypeid || 1985 typmod != tupDesc->tdtypmod)) 1986 { 1987 tupDesc = lookup_rowtype_tupdesc(type_id, typmod); 1988 /* Drop pin acquired by lookup_rowtype_tupdesc */ 1989 ReleaseTupleDesc(tupDesc); 1990 rowcache->cacheptr = (void *) tupDesc; 1991 rowcache->tupdesc_id = 0; /* not a valid value for non-RECORD */ 1992 if (changed) 1993 *changed = true; 1994 } 1995 return tupDesc; 1996 } 1997 } 1998 1999 2000 /* 2001 * Fast-path functions, for very simple expressions 2002 */ 2003 2004 /* Simple reference to inner Var */ 2005 static Datum 2006 ExecJustInnerVar(ExprState *state, ExprContext *econtext, bool *isnull) 2007 { 2008 ExprEvalStep *op = &state->steps[1]; 2009 int attnum = op->d.var.attnum + 1; 2010 TupleTableSlot *slot = econtext->ecxt_innertuple; 2011 2012 CheckOpSlotCompatibility(&state->steps[0], slot); 2013 2014 /* 2015 * Since we use slot_getattr(), we don't need to implement the FETCHSOME 2016 * step explicitly, and we also needn't Assert that the attnum is in range 2017 * --- slot_getattr() will take care of any problems. 2018 */ 2019 return slot_getattr(slot, attnum, isnull); 2020 } 2021 2022 /* Simple reference to outer Var */ 2023 static Datum 2024 ExecJustOuterVar(ExprState *state, ExprContext *econtext, bool *isnull) 2025 { 2026 ExprEvalStep *op = &state->steps[1]; 2027 int attnum = op->d.var.attnum + 1; 2028 TupleTableSlot *slot = econtext->ecxt_outertuple; 2029 2030 CheckOpSlotCompatibility(&state->steps[0], slot); 2031 2032 /* See comments in ExecJustInnerVar */ 2033 return slot_getattr(slot, attnum, isnull); 2034 } 2035 2036 /* Simple reference to scan Var */ 2037 static Datum 2038 ExecJustScanVar(ExprState *state, ExprContext *econtext, bool *isnull) 2039 { 2040 ExprEvalStep *op = &state->steps[1]; 2041 int attnum = op->d.var.attnum + 1; 2042 TupleTableSlot *slot = econtext->ecxt_scantuple; 2043 2044 CheckOpSlotCompatibility(&state->steps[0], slot); 2045 2046 /* See comments in ExecJustInnerVar */ 2047 return slot_getattr(slot, attnum, isnull); 2048 } 2049 2050 /* Simple Const expression */ 2051 static Datum 2052 ExecJustConst(ExprState *state, ExprContext *econtext, bool *isnull) 2053 { 2054 ExprEvalStep *op = &state->steps[0]; 2055 2056 *isnull = op->d.constval.isnull; 2057 return op->d.constval.value; 2058 } 2059 2060 /* Evaluate inner Var and assign to appropriate column of result tuple */ 2061 static Datum 2062 ExecJustAssignInnerVar(ExprState *state, ExprContext *econtext, bool *isnull) 2063 { 2064 ExprEvalStep *op = &state->steps[1]; 2065 int attnum = op->d.assign_var.attnum + 1; 2066 int resultnum = op->d.assign_var.resultnum; 2067 TupleTableSlot *inslot = econtext->ecxt_innertuple; 2068 TupleTableSlot *outslot = state->resultslot; 2069 2070 CheckOpSlotCompatibility(&state->steps[0], inslot); 2071 2072 /* 2073 * We do not need CheckVarSlotCompatibility here; that was taken care of 2074 * at compilation time. 2075 * 2076 * Since we use slot_getattr(), we don't need to implement the FETCHSOME 2077 * step explicitly, and we also needn't Assert that the attnum is in range 2078 * --- slot_getattr() will take care of any problems. Nonetheless, check 2079 * that resultnum is in range. 2080 */ 2081 Assert(resultnum >= 0 && resultnum < outslot->tts_tupleDescriptor->natts); 2082 outslot->tts_values[resultnum] = 2083 slot_getattr(inslot, attnum, &outslot->tts_isnull[resultnum]); 2084 return 0; 2085 } 2086 2087 /* Evaluate outer Var and assign to appropriate column of result tuple */ 2088 static Datum 2089 ExecJustAssignOuterVar(ExprState *state, ExprContext *econtext, bool *isnull) 2090 { 2091 ExprEvalStep *op = &state->steps[1]; 2092 int attnum = op->d.assign_var.attnum + 1; 2093 int resultnum = op->d.assign_var.resultnum; 2094 TupleTableSlot *inslot = econtext->ecxt_outertuple; 2095 TupleTableSlot *outslot = state->resultslot; 2096 2097 CheckOpSlotCompatibility(&state->steps[0], inslot); 2098 2099 /* See comments in ExecJustAssignInnerVar */ 2100 Assert(resultnum >= 0 && resultnum < outslot->tts_tupleDescriptor->natts); 2101 outslot->tts_values[resultnum] = 2102 slot_getattr(inslot, attnum, &outslot->tts_isnull[resultnum]); 2103 return 0; 2104 } 2105 2106 /* Evaluate scan Var and assign to appropriate column of result tuple */ 2107 static Datum 2108 ExecJustAssignScanVar(ExprState *state, ExprContext *econtext, bool *isnull) 2109 { 2110 ExprEvalStep *op = &state->steps[1]; 2111 int attnum = op->d.assign_var.attnum + 1; 2112 int resultnum = op->d.assign_var.resultnum; 2113 TupleTableSlot *inslot = econtext->ecxt_scantuple; 2114 TupleTableSlot *outslot = state->resultslot; 2115 2116 CheckOpSlotCompatibility(&state->steps[0], inslot); 2117 2118 /* See comments in ExecJustAssignInnerVar */ 2119 Assert(resultnum >= 0 && resultnum < outslot->tts_tupleDescriptor->natts); 2120 outslot->tts_values[resultnum] = 2121 slot_getattr(inslot, attnum, &outslot->tts_isnull[resultnum]); 2122 return 0; 2123 } 2124 2125 /* Evaluate CASE_TESTVAL and apply a strict function to it */ 2126 static Datum 2127 ExecJustApplyFuncToCase(ExprState *state, ExprContext *econtext, bool *isnull) 2128 { 2129 ExprEvalStep *op = &state->steps[0]; 2130 FunctionCallInfo fcinfo; 2131 NullableDatum *args; 2132 int argno; 2133 Datum d; 2134 2135 /* 2136 * XXX with some redesign of the CaseTestExpr mechanism, maybe we could 2137 * get rid of this data shuffling? 2138 */ 2139 *op->resvalue = *op->d.casetest.value; 2140 *op->resnull = *op->d.casetest.isnull; 2141 2142 op++; 2143 2144 fcinfo = op->d.func.fcinfo_data; 2145 args = fcinfo->args; 2146 2147 /* strict function, so check for NULL args */ 2148 for (argno = 0; argno < op->d.func.nargs; argno++) 2149 { 2150 if (args[argno].isnull) 2151 { 2152 *isnull = true; 2153 return (Datum) 0; 2154 } 2155 } 2156 fcinfo->isnull = false; 2157 d = op->d.func.fn_addr(fcinfo); 2158 *isnull = fcinfo->isnull; 2159 return d; 2160 } 2161 2162 #if defined(EEO_USE_COMPUTED_GOTO) 2163 /* 2164 * Comparator used when building address->opcode lookup table for 2165 * ExecEvalStepOp() in the threaded dispatch case. 2166 */ 2167 static int 2168 dispatch_compare_ptr(const void *a, const void *b) 2169 { 2170 const ExprEvalOpLookup *la = (const ExprEvalOpLookup *) a; 2171 const ExprEvalOpLookup *lb = (const ExprEvalOpLookup *) b; 2172 2173 if (la->opcode < lb->opcode) 2174 return -1; 2175 else if (la->opcode > lb->opcode) 2176 return 1; 2177 return 0; 2178 } 2179 #endif 2180 2181 /* 2182 * Do one-time initialization of interpretation machinery. 2183 */ 2184 static void 2185 ExecInitInterpreter(void) 2186 { 2187 #if defined(EEO_USE_COMPUTED_GOTO) 2188 /* Set up externally-visible pointer to dispatch table */ 2189 if (dispatch_table == NULL) 2190 { 2191 int i; 2192 2193 dispatch_table = (const void **) 2194 DatumGetPointer(ExecInterpExpr(NULL, NULL, NULL)); 2195 2196 /* build reverse lookup table */ 2197 for (i = 0; i < EEOP_LAST; i++) 2198 { 2199 reverse_dispatch_table[i].opcode = dispatch_table[i]; 2200 reverse_dispatch_table[i].op = (ExprEvalOp) i; 2201 } 2202 2203 /* make it bsearch()able */ 2204 qsort(reverse_dispatch_table, 2205 EEOP_LAST /* nmembers */ , 2206 sizeof(ExprEvalOpLookup), 2207 dispatch_compare_ptr); 2208 } 2209 #endif 2210 } 2211 2212 /* 2213 * Function to return the opcode of an expression step. 2214 * 2215 * When direct-threading is in use, ExprState->opcode isn't easily 2216 * decipherable. This function returns the appropriate enum member. 2217 */ 2218 ExprEvalOp 2219 ExecEvalStepOp(ExprState *state, ExprEvalStep *op) 2220 { 2221 #if defined(EEO_USE_COMPUTED_GOTO) 2222 if (state->flags & EEO_FLAG_DIRECT_THREADED) 2223 { 2224 ExprEvalOpLookup key; 2225 ExprEvalOpLookup *res; 2226 2227 key.opcode = (void *) op->opcode; 2228 res = bsearch(&key, 2229 reverse_dispatch_table, 2230 EEOP_LAST /* nmembers */ , 2231 sizeof(ExprEvalOpLookup), 2232 dispatch_compare_ptr); 2233 Assert(res); /* unknown ops shouldn't get looked up */ 2234 return res->op; 2235 } 2236 #endif 2237 return (ExprEvalOp) op->opcode; 2238 } 2239 2240 2241 /* 2242 * Out-of-line helper functions for complex instructions. 2243 */ 2244 2245 /* 2246 * Evaluate EEOP_FUNCEXPR_FUSAGE 2247 */ 2248 void 2249 ExecEvalFuncExprFusage(ExprState *state, ExprEvalStep *op, 2250 ExprContext *econtext) 2251 { 2252 FunctionCallInfo fcinfo = op->d.func.fcinfo_data; 2253 PgStat_FunctionCallUsage fcusage; 2254 Datum d; 2255 2256 pgstat_init_function_usage(fcinfo, &fcusage); 2257 2258 fcinfo->isnull = false; 2259 d = op->d.func.fn_addr(fcinfo); 2260 *op->resvalue = d; 2261 *op->resnull = fcinfo->isnull; 2262 2263 pgstat_end_function_usage(&fcusage, true); 2264 } 2265 2266 /* 2267 * Evaluate EEOP_FUNCEXPR_STRICT_FUSAGE 2268 */ 2269 void 2270 ExecEvalFuncExprStrictFusage(ExprState *state, ExprEvalStep *op, 2271 ExprContext *econtext) 2272 { 2273 2274 FunctionCallInfo fcinfo = op->d.func.fcinfo_data; 2275 PgStat_FunctionCallUsage fcusage; 2276 NullableDatum *args = fcinfo->args; 2277 int argno; 2278 Datum d; 2279 2280 /* strict function, so check for NULL args */ 2281 for (argno = 0; argno < op->d.func.nargs; argno++) 2282 { 2283 if (args[argno].isnull) 2284 { 2285 *op->resnull = true; 2286 return; 2287 } 2288 } 2289 2290 pgstat_init_function_usage(fcinfo, &fcusage); 2291 2292 fcinfo->isnull = false; 2293 d = op->d.func.fn_addr(fcinfo); 2294 *op->resvalue = d; 2295 *op->resnull = fcinfo->isnull; 2296 2297 pgstat_end_function_usage(&fcusage, true); 2298 } 2299 2300 /* 2301 * Evaluate a PARAM_EXEC parameter. 2302 * 2303 * PARAM_EXEC params (internal executor parameters) are stored in the 2304 * ecxt_param_exec_vals array, and can be accessed by array index. 2305 */ 2306 void 2307 ExecEvalParamExec(ExprState *state, ExprEvalStep *op, ExprContext *econtext) 2308 { 2309 ParamExecData *prm; 2310 2311 prm = &(econtext->ecxt_param_exec_vals[op->d.param.paramid]); 2312 if (unlikely(prm->execPlan != NULL)) 2313 { 2314 /* Parameter not evaluated yet, so go do it */ 2315 ExecSetParamPlan(prm->execPlan, econtext); 2316 /* ExecSetParamPlan should have processed this param... */ 2317 Assert(prm->execPlan == NULL); 2318 } 2319 *op->resvalue = prm->value; 2320 *op->resnull = prm->isnull; 2321 } 2322 2323 /* 2324 * Evaluate a PARAM_EXTERN parameter. 2325 * 2326 * PARAM_EXTERN parameters must be sought in ecxt_param_list_info. 2327 */ 2328 void 2329 ExecEvalParamExtern(ExprState *state, ExprEvalStep *op, ExprContext *econtext) 2330 { 2331 ParamListInfo paramInfo = econtext->ecxt_param_list_info; 2332 int paramId = op->d.param.paramid; 2333 2334 if (likely(paramInfo && 2335 paramId > 0 && paramId <= paramInfo->numParams)) 2336 { 2337 ParamExternData *prm; 2338 ParamExternData prmdata; 2339 2340 /* give hook a chance in case parameter is dynamic */ 2341 if (paramInfo->paramFetch != NULL) 2342 prm = paramInfo->paramFetch(paramInfo, paramId, false, &prmdata); 2343 else 2344 prm = ¶mInfo->params[paramId - 1]; 2345 2346 if (likely(OidIsValid(prm->ptype))) 2347 { 2348 /* safety check in case hook did something unexpected */ 2349 if (unlikely(prm->ptype != op->d.param.paramtype)) 2350 ereport(ERROR, 2351 (errcode(ERRCODE_DATATYPE_MISMATCH), 2352 errmsg("type of parameter %d (%s) does not match that when preparing the plan (%s)", 2353 paramId, 2354 format_type_be(prm->ptype), 2355 format_type_be(op->d.param.paramtype)))); 2356 *op->resvalue = prm->value; 2357 *op->resnull = prm->isnull; 2358 return; 2359 } 2360 } 2361 2362 ereport(ERROR, 2363 (errcode(ERRCODE_UNDEFINED_OBJECT), 2364 errmsg("no value found for parameter %d", paramId))); 2365 } 2366 2367 /* 2368 * Evaluate a SQLValueFunction expression. 2369 */ 2370 void 2371 ExecEvalSQLValueFunction(ExprState *state, ExprEvalStep *op) 2372 { 2373 LOCAL_FCINFO(fcinfo, 0); 2374 SQLValueFunction *svf = op->d.sqlvaluefunction.svf; 2375 2376 *op->resnull = false; 2377 2378 /* 2379 * Note: current_schema() can return NULL. current_user() etc currently 2380 * cannot, but might as well code those cases the same way for safety. 2381 */ 2382 switch (svf->op) 2383 { 2384 case SVFOP_CURRENT_DATE: 2385 *op->resvalue = DateADTGetDatum(GetSQLCurrentDate()); 2386 break; 2387 case SVFOP_CURRENT_TIME: 2388 case SVFOP_CURRENT_TIME_N: 2389 *op->resvalue = TimeTzADTPGetDatum(GetSQLCurrentTime(svf->typmod)); 2390 break; 2391 case SVFOP_CURRENT_TIMESTAMP: 2392 case SVFOP_CURRENT_TIMESTAMP_N: 2393 *op->resvalue = TimestampTzGetDatum(GetSQLCurrentTimestamp(svf->typmod)); 2394 break; 2395 case SVFOP_LOCALTIME: 2396 case SVFOP_LOCALTIME_N: 2397 *op->resvalue = TimeADTGetDatum(GetSQLLocalTime(svf->typmod)); 2398 break; 2399 case SVFOP_LOCALTIMESTAMP: 2400 case SVFOP_LOCALTIMESTAMP_N: 2401 *op->resvalue = TimestampGetDatum(GetSQLLocalTimestamp(svf->typmod)); 2402 break; 2403 case SVFOP_CURRENT_ROLE: 2404 case SVFOP_CURRENT_USER: 2405 case SVFOP_USER: 2406 InitFunctionCallInfoData(*fcinfo, NULL, 0, InvalidOid, NULL, NULL); 2407 *op->resvalue = current_user(fcinfo); 2408 *op->resnull = fcinfo->isnull; 2409 break; 2410 case SVFOP_SESSION_USER: 2411 InitFunctionCallInfoData(*fcinfo, NULL, 0, InvalidOid, NULL, NULL); 2412 *op->resvalue = session_user(fcinfo); 2413 *op->resnull = fcinfo->isnull; 2414 break; 2415 case SVFOP_CURRENT_CATALOG: 2416 InitFunctionCallInfoData(*fcinfo, NULL, 0, InvalidOid, NULL, NULL); 2417 *op->resvalue = current_database(fcinfo); 2418 *op->resnull = fcinfo->isnull; 2419 break; 2420 case SVFOP_CURRENT_SCHEMA: 2421 InitFunctionCallInfoData(*fcinfo, NULL, 0, InvalidOid, NULL, NULL); 2422 *op->resvalue = current_schema(fcinfo); 2423 *op->resnull = fcinfo->isnull; 2424 break; 2425 } 2426 } 2427 2428 /* 2429 * Raise error if a CURRENT OF expression is evaluated. 2430 * 2431 * The planner should convert CURRENT OF into a TidScan qualification, or some 2432 * other special handling in a ForeignScan node. So we have to be able to do 2433 * ExecInitExpr on a CurrentOfExpr, but we shouldn't ever actually execute it. 2434 * If we get here, we suppose we must be dealing with CURRENT OF on a foreign 2435 * table whose FDW doesn't handle it, and complain accordingly. 2436 */ 2437 void 2438 ExecEvalCurrentOfExpr(ExprState *state, ExprEvalStep *op) 2439 { 2440 ereport(ERROR, 2441 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), 2442 errmsg("WHERE CURRENT OF is not supported for this table type"))); 2443 } 2444 2445 /* 2446 * Evaluate NextValueExpr. 2447 */ 2448 void 2449 ExecEvalNextValueExpr(ExprState *state, ExprEvalStep *op) 2450 { 2451 int64 newval = nextval_internal(op->d.nextvalueexpr.seqid, false); 2452 2453 switch (op->d.nextvalueexpr.seqtypid) 2454 { 2455 case INT2OID: 2456 *op->resvalue = Int16GetDatum((int16) newval); 2457 break; 2458 case INT4OID: 2459 *op->resvalue = Int32GetDatum((int32) newval); 2460 break; 2461 case INT8OID: 2462 *op->resvalue = Int64GetDatum((int64) newval); 2463 break; 2464 default: 2465 elog(ERROR, "unsupported sequence type %u", 2466 op->d.nextvalueexpr.seqtypid); 2467 } 2468 *op->resnull = false; 2469 } 2470 2471 /* 2472 * Evaluate NullTest / IS NULL for rows. 2473 */ 2474 void 2475 ExecEvalRowNull(ExprState *state, ExprEvalStep *op, ExprContext *econtext) 2476 { 2477 ExecEvalRowNullInt(state, op, econtext, true); 2478 } 2479 2480 /* 2481 * Evaluate NullTest / IS NOT NULL for rows. 2482 */ 2483 void 2484 ExecEvalRowNotNull(ExprState *state, ExprEvalStep *op, ExprContext *econtext) 2485 { 2486 ExecEvalRowNullInt(state, op, econtext, false); 2487 } 2488 2489 /* Common code for IS [NOT] NULL on a row value */ 2490 static void 2491 ExecEvalRowNullInt(ExprState *state, ExprEvalStep *op, 2492 ExprContext *econtext, bool checkisnull) 2493 { 2494 Datum value = *op->resvalue; 2495 bool isnull = *op->resnull; 2496 HeapTupleHeader tuple; 2497 Oid tupType; 2498 int32 tupTypmod; 2499 TupleDesc tupDesc; 2500 HeapTupleData tmptup; 2501 int att; 2502 2503 *op->resnull = false; 2504 2505 /* NULL row variables are treated just as NULL scalar columns */ 2506 if (isnull) 2507 { 2508 *op->resvalue = BoolGetDatum(checkisnull); 2509 return; 2510 } 2511 2512 /* 2513 * The SQL standard defines IS [NOT] NULL for a non-null rowtype argument 2514 * as: 2515 * 2516 * "R IS NULL" is true if every field is the null value. 2517 * 2518 * "R IS NOT NULL" is true if no field is the null value. 2519 * 2520 * This definition is (apparently intentionally) not recursive; so our 2521 * tests on the fields are primitive attisnull tests, not recursive checks 2522 * to see if they are all-nulls or no-nulls rowtypes. 2523 * 2524 * The standard does not consider the possibility of zero-field rows, but 2525 * here we consider them to vacuously satisfy both predicates. 2526 */ 2527 2528 tuple = DatumGetHeapTupleHeader(value); 2529 2530 tupType = HeapTupleHeaderGetTypeId(tuple); 2531 tupTypmod = HeapTupleHeaderGetTypMod(tuple); 2532 2533 /* Lookup tupdesc if first time through or if type changes */ 2534 tupDesc = get_cached_rowtype(tupType, tupTypmod, 2535 &op->d.nulltest_row.rowcache, NULL); 2536 2537 /* 2538 * heap_attisnull needs a HeapTuple not a bare HeapTupleHeader. 2539 */ 2540 tmptup.t_len = HeapTupleHeaderGetDatumLength(tuple); 2541 tmptup.t_data = tuple; 2542 2543 for (att = 1; att <= tupDesc->natts; att++) 2544 { 2545 /* ignore dropped columns */ 2546 if (TupleDescAttr(tupDesc, att - 1)->attisdropped) 2547 continue; 2548 if (heap_attisnull(&tmptup, att, tupDesc)) 2549 { 2550 /* null field disproves IS NOT NULL */ 2551 if (!checkisnull) 2552 { 2553 *op->resvalue = BoolGetDatum(false); 2554 return; 2555 } 2556 } 2557 else 2558 { 2559 /* non-null field disproves IS NULL */ 2560 if (checkisnull) 2561 { 2562 *op->resvalue = BoolGetDatum(false); 2563 return; 2564 } 2565 } 2566 } 2567 2568 *op->resvalue = BoolGetDatum(true); 2569 } 2570 2571 /* 2572 * Evaluate an ARRAY[] expression. 2573 * 2574 * The individual array elements (or subarrays) have already been evaluated 2575 * into op->d.arrayexpr.elemvalues[]/elemnulls[]. 2576 */ 2577 void 2578 ExecEvalArrayExpr(ExprState *state, ExprEvalStep *op) 2579 { 2580 ArrayType *result; 2581 Oid element_type = op->d.arrayexpr.elemtype; 2582 int nelems = op->d.arrayexpr.nelems; 2583 int ndims = 0; 2584 int dims[MAXDIM]; 2585 int lbs[MAXDIM]; 2586 2587 /* Set non-null as default */ 2588 *op->resnull = false; 2589 2590 if (!op->d.arrayexpr.multidims) 2591 { 2592 /* Elements are presumably of scalar type */ 2593 Datum *dvalues = op->d.arrayexpr.elemvalues; 2594 bool *dnulls = op->d.arrayexpr.elemnulls; 2595 2596 /* setup for 1-D array of the given length */ 2597 ndims = 1; 2598 dims[0] = nelems; 2599 lbs[0] = 1; 2600 2601 result = construct_md_array(dvalues, dnulls, ndims, dims, lbs, 2602 element_type, 2603 op->d.arrayexpr.elemlength, 2604 op->d.arrayexpr.elembyval, 2605 op->d.arrayexpr.elemalign); 2606 } 2607 else 2608 { 2609 /* Must be nested array expressions */ 2610 int nbytes = 0; 2611 int nitems = 0; 2612 int outer_nelems = 0; 2613 int elem_ndims = 0; 2614 int *elem_dims = NULL; 2615 int *elem_lbs = NULL; 2616 bool firstone = true; 2617 bool havenulls = false; 2618 bool haveempty = false; 2619 char **subdata; 2620 bits8 **subbitmaps; 2621 int *subbytes; 2622 int *subnitems; 2623 int32 dataoffset; 2624 char *dat; 2625 int iitem; 2626 int elemoff; 2627 int i; 2628 2629 subdata = (char **) palloc(nelems * sizeof(char *)); 2630 subbitmaps = (bits8 **) palloc(nelems * sizeof(bits8 *)); 2631 subbytes = (int *) palloc(nelems * sizeof(int)); 2632 subnitems = (int *) palloc(nelems * sizeof(int)); 2633 2634 /* loop through and get data area from each element */ 2635 for (elemoff = 0; elemoff < nelems; elemoff++) 2636 { 2637 Datum arraydatum; 2638 bool eisnull; 2639 ArrayType *array; 2640 int this_ndims; 2641 2642 arraydatum = op->d.arrayexpr.elemvalues[elemoff]; 2643 eisnull = op->d.arrayexpr.elemnulls[elemoff]; 2644 2645 /* temporarily ignore null subarrays */ 2646 if (eisnull) 2647 { 2648 haveempty = true; 2649 continue; 2650 } 2651 2652 array = DatumGetArrayTypeP(arraydatum); 2653 2654 /* run-time double-check on element type */ 2655 if (element_type != ARR_ELEMTYPE(array)) 2656 ereport(ERROR, 2657 (errcode(ERRCODE_DATATYPE_MISMATCH), 2658 errmsg("cannot merge incompatible arrays"), 2659 errdetail("Array with element type %s cannot be " 2660 "included in ARRAY construct with element type %s.", 2661 format_type_be(ARR_ELEMTYPE(array)), 2662 format_type_be(element_type)))); 2663 2664 this_ndims = ARR_NDIM(array); 2665 /* temporarily ignore zero-dimensional subarrays */ 2666 if (this_ndims <= 0) 2667 { 2668 haveempty = true; 2669 continue; 2670 } 2671 2672 if (firstone) 2673 { 2674 /* Get sub-array details from first member */ 2675 elem_ndims = this_ndims; 2676 ndims = elem_ndims + 1; 2677 if (ndims <= 0 || ndims > MAXDIM) 2678 ereport(ERROR, 2679 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), 2680 errmsg("number of array dimensions (%d) exceeds " \ 2681 "the maximum allowed (%d)", ndims, MAXDIM))); 2682 2683 elem_dims = (int *) palloc(elem_ndims * sizeof(int)); 2684 memcpy(elem_dims, ARR_DIMS(array), elem_ndims * sizeof(int)); 2685 elem_lbs = (int *) palloc(elem_ndims * sizeof(int)); 2686 memcpy(elem_lbs, ARR_LBOUND(array), elem_ndims * sizeof(int)); 2687 2688 firstone = false; 2689 } 2690 else 2691 { 2692 /* Check other sub-arrays are compatible */ 2693 if (elem_ndims != this_ndims || 2694 memcmp(elem_dims, ARR_DIMS(array), 2695 elem_ndims * sizeof(int)) != 0 || 2696 memcmp(elem_lbs, ARR_LBOUND(array), 2697 elem_ndims * sizeof(int)) != 0) 2698 ereport(ERROR, 2699 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), 2700 errmsg("multidimensional arrays must have array " 2701 "expressions with matching dimensions"))); 2702 } 2703 2704 subdata[outer_nelems] = ARR_DATA_PTR(array); 2705 subbitmaps[outer_nelems] = ARR_NULLBITMAP(array); 2706 subbytes[outer_nelems] = ARR_SIZE(array) - ARR_DATA_OFFSET(array); 2707 nbytes += subbytes[outer_nelems]; 2708 subnitems[outer_nelems] = ArrayGetNItems(this_ndims, 2709 ARR_DIMS(array)); 2710 nitems += subnitems[outer_nelems]; 2711 havenulls |= ARR_HASNULL(array); 2712 outer_nelems++; 2713 } 2714 2715 /* 2716 * If all items were null or empty arrays, return an empty array; 2717 * otherwise, if some were and some weren't, raise error. (Note: we 2718 * must special-case this somehow to avoid trying to generate a 1-D 2719 * array formed from empty arrays. It's not ideal...) 2720 */ 2721 if (haveempty) 2722 { 2723 if (ndims == 0) /* didn't find any nonempty array */ 2724 { 2725 *op->resvalue = PointerGetDatum(construct_empty_array(element_type)); 2726 return; 2727 } 2728 ereport(ERROR, 2729 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), 2730 errmsg("multidimensional arrays must have array " 2731 "expressions with matching dimensions"))); 2732 } 2733 2734 /* setup for multi-D array */ 2735 dims[0] = outer_nelems; 2736 lbs[0] = 1; 2737 for (i = 1; i < ndims; i++) 2738 { 2739 dims[i] = elem_dims[i - 1]; 2740 lbs[i] = elem_lbs[i - 1]; 2741 } 2742 2743 /* check for subscript overflow */ 2744 (void) ArrayGetNItems(ndims, dims); 2745 ArrayCheckBounds(ndims, dims, lbs); 2746 2747 if (havenulls) 2748 { 2749 dataoffset = ARR_OVERHEAD_WITHNULLS(ndims, nitems); 2750 nbytes += dataoffset; 2751 } 2752 else 2753 { 2754 dataoffset = 0; /* marker for no null bitmap */ 2755 nbytes += ARR_OVERHEAD_NONULLS(ndims); 2756 } 2757 2758 result = (ArrayType *) palloc(nbytes); 2759 SET_VARSIZE(result, nbytes); 2760 result->ndim = ndims; 2761 result->dataoffset = dataoffset; 2762 result->elemtype = element_type; 2763 memcpy(ARR_DIMS(result), dims, ndims * sizeof(int)); 2764 memcpy(ARR_LBOUND(result), lbs, ndims * sizeof(int)); 2765 2766 dat = ARR_DATA_PTR(result); 2767 iitem = 0; 2768 for (i = 0; i < outer_nelems; i++) 2769 { 2770 memcpy(dat, subdata[i], subbytes[i]); 2771 dat += subbytes[i]; 2772 if (havenulls) 2773 array_bitmap_copy(ARR_NULLBITMAP(result), iitem, 2774 subbitmaps[i], 0, 2775 subnitems[i]); 2776 iitem += subnitems[i]; 2777 } 2778 } 2779 2780 *op->resvalue = PointerGetDatum(result); 2781 } 2782 2783 /* 2784 * Evaluate an ArrayCoerceExpr expression. 2785 * 2786 * Source array is in step's result variable. 2787 */ 2788 void 2789 ExecEvalArrayCoerce(ExprState *state, ExprEvalStep *op, ExprContext *econtext) 2790 { 2791 Datum arraydatum; 2792 2793 /* NULL array -> NULL result */ 2794 if (*op->resnull) 2795 return; 2796 2797 arraydatum = *op->resvalue; 2798 2799 /* 2800 * If it's binary-compatible, modify the element type in the array header, 2801 * but otherwise leave the array as we received it. 2802 */ 2803 if (op->d.arraycoerce.elemexprstate == NULL) 2804 { 2805 /* Detoast input array if necessary, and copy in any case */ 2806 ArrayType *array = DatumGetArrayTypePCopy(arraydatum); 2807 2808 ARR_ELEMTYPE(array) = op->d.arraycoerce.resultelemtype; 2809 *op->resvalue = PointerGetDatum(array); 2810 return; 2811 } 2812 2813 /* 2814 * Use array_map to apply the sub-expression to each array element. 2815 */ 2816 *op->resvalue = array_map(arraydatum, 2817 op->d.arraycoerce.elemexprstate, 2818 econtext, 2819 op->d.arraycoerce.resultelemtype, 2820 op->d.arraycoerce.amstate); 2821 } 2822 2823 /* 2824 * Evaluate a ROW() expression. 2825 * 2826 * The individual columns have already been evaluated into 2827 * op->d.row.elemvalues[]/elemnulls[]. 2828 */ 2829 void 2830 ExecEvalRow(ExprState *state, ExprEvalStep *op) 2831 { 2832 HeapTuple tuple; 2833 2834 /* build tuple from evaluated field values */ 2835 tuple = heap_form_tuple(op->d.row.tupdesc, 2836 op->d.row.elemvalues, 2837 op->d.row.elemnulls); 2838 2839 *op->resvalue = HeapTupleGetDatum(tuple); 2840 *op->resnull = false; 2841 } 2842 2843 /* 2844 * Evaluate GREATEST() or LEAST() expression (note this is *not* MIN()/MAX()). 2845 * 2846 * All of the to-be-compared expressions have already been evaluated into 2847 * op->d.minmax.values[]/nulls[]. 2848 */ 2849 void 2850 ExecEvalMinMax(ExprState *state, ExprEvalStep *op) 2851 { 2852 Datum *values = op->d.minmax.values; 2853 bool *nulls = op->d.minmax.nulls; 2854 FunctionCallInfo fcinfo = op->d.minmax.fcinfo_data; 2855 MinMaxOp operator = op->d.minmax.op; 2856 int off; 2857 2858 /* set at initialization */ 2859 Assert(fcinfo->args[0].isnull == false); 2860 Assert(fcinfo->args[1].isnull == false); 2861 2862 /* default to null result */ 2863 *op->resnull = true; 2864 2865 for (off = 0; off < op->d.minmax.nelems; off++) 2866 { 2867 /* ignore NULL inputs */ 2868 if (nulls[off]) 2869 continue; 2870 2871 if (*op->resnull) 2872 { 2873 /* first nonnull input, adopt value */ 2874 *op->resvalue = values[off]; 2875 *op->resnull = false; 2876 } 2877 else 2878 { 2879 int cmpresult; 2880 2881 /* apply comparison function */ 2882 fcinfo->args[0].value = *op->resvalue; 2883 fcinfo->args[1].value = values[off]; 2884 2885 fcinfo->isnull = false; 2886 cmpresult = DatumGetInt32(FunctionCallInvoke(fcinfo)); 2887 if (fcinfo->isnull) /* probably should not happen */ 2888 continue; 2889 2890 if (cmpresult > 0 && operator == IS_LEAST) 2891 *op->resvalue = values[off]; 2892 else if (cmpresult < 0 && operator == IS_GREATEST) 2893 *op->resvalue = values[off]; 2894 } 2895 } 2896 } 2897 2898 /* 2899 * Evaluate a FieldSelect node. 2900 * 2901 * Source record is in step's result variable. 2902 */ 2903 void 2904 ExecEvalFieldSelect(ExprState *state, ExprEvalStep *op, ExprContext *econtext) 2905 { 2906 AttrNumber fieldnum = op->d.fieldselect.fieldnum; 2907 Datum tupDatum; 2908 HeapTupleHeader tuple; 2909 Oid tupType; 2910 int32 tupTypmod; 2911 TupleDesc tupDesc; 2912 Form_pg_attribute attr; 2913 HeapTupleData tmptup; 2914 2915 /* NULL record -> NULL result */ 2916 if (*op->resnull) 2917 return; 2918 2919 tupDatum = *op->resvalue; 2920 2921 /* We can special-case expanded records for speed */ 2922 if (VARATT_IS_EXTERNAL_EXPANDED(DatumGetPointer(tupDatum))) 2923 { 2924 ExpandedRecordHeader *erh = (ExpandedRecordHeader *) DatumGetEOHP(tupDatum); 2925 2926 Assert(erh->er_magic == ER_MAGIC); 2927 2928 /* Extract record's TupleDesc */ 2929 tupDesc = expanded_record_get_tupdesc(erh); 2930 2931 /* 2932 * Find field's attr record. Note we don't support system columns 2933 * here: a datum tuple doesn't have valid values for most of the 2934 * interesting system columns anyway. 2935 */ 2936 if (fieldnum <= 0) /* should never happen */ 2937 elog(ERROR, "unsupported reference to system column %d in FieldSelect", 2938 fieldnum); 2939 if (fieldnum > tupDesc->natts) /* should never happen */ 2940 elog(ERROR, "attribute number %d exceeds number of columns %d", 2941 fieldnum, tupDesc->natts); 2942 attr = TupleDescAttr(tupDesc, fieldnum - 1); 2943 2944 /* Check for dropped column, and force a NULL result if so */ 2945 if (attr->attisdropped) 2946 { 2947 *op->resnull = true; 2948 return; 2949 } 2950 2951 /* Check for type mismatch --- possible after ALTER COLUMN TYPE? */ 2952 /* As in CheckVarSlotCompatibility, we should but can't check typmod */ 2953 if (op->d.fieldselect.resulttype != attr->atttypid) 2954 ereport(ERROR, 2955 (errcode(ERRCODE_DATATYPE_MISMATCH), 2956 errmsg("attribute %d has wrong type", fieldnum), 2957 errdetail("Table has type %s, but query expects %s.", 2958 format_type_be(attr->atttypid), 2959 format_type_be(op->d.fieldselect.resulttype)))); 2960 2961 /* extract the field */ 2962 *op->resvalue = expanded_record_get_field(erh, fieldnum, 2963 op->resnull); 2964 } 2965 else 2966 { 2967 /* Get the composite datum and extract its type fields */ 2968 tuple = DatumGetHeapTupleHeader(tupDatum); 2969 2970 tupType = HeapTupleHeaderGetTypeId(tuple); 2971 tupTypmod = HeapTupleHeaderGetTypMod(tuple); 2972 2973 /* Lookup tupdesc if first time through or if type changes */ 2974 tupDesc = get_cached_rowtype(tupType, tupTypmod, 2975 &op->d.fieldselect.rowcache, NULL); 2976 2977 /* 2978 * Find field's attr record. Note we don't support system columns 2979 * here: a datum tuple doesn't have valid values for most of the 2980 * interesting system columns anyway. 2981 */ 2982 if (fieldnum <= 0) /* should never happen */ 2983 elog(ERROR, "unsupported reference to system column %d in FieldSelect", 2984 fieldnum); 2985 if (fieldnum > tupDesc->natts) /* should never happen */ 2986 elog(ERROR, "attribute number %d exceeds number of columns %d", 2987 fieldnum, tupDesc->natts); 2988 attr = TupleDescAttr(tupDesc, fieldnum - 1); 2989 2990 /* Check for dropped column, and force a NULL result if so */ 2991 if (attr->attisdropped) 2992 { 2993 *op->resnull = true; 2994 return; 2995 } 2996 2997 /* Check for type mismatch --- possible after ALTER COLUMN TYPE? */ 2998 /* As in CheckVarSlotCompatibility, we should but can't check typmod */ 2999 if (op->d.fieldselect.resulttype != attr->atttypid) 3000 ereport(ERROR, 3001 (errcode(ERRCODE_DATATYPE_MISMATCH), 3002 errmsg("attribute %d has wrong type", fieldnum), 3003 errdetail("Table has type %s, but query expects %s.", 3004 format_type_be(attr->atttypid), 3005 format_type_be(op->d.fieldselect.resulttype)))); 3006 3007 /* heap_getattr needs a HeapTuple not a bare HeapTupleHeader */ 3008 tmptup.t_len = HeapTupleHeaderGetDatumLength(tuple); 3009 tmptup.t_data = tuple; 3010 3011 /* extract the field */ 3012 *op->resvalue = heap_getattr(&tmptup, 3013 fieldnum, 3014 tupDesc, 3015 op->resnull); 3016 } 3017 } 3018 3019 /* 3020 * Deform source tuple, filling in the step's values/nulls arrays, before 3021 * evaluating individual new values as part of a FieldStore expression. 3022 * Subsequent steps will overwrite individual elements of the values/nulls 3023 * arrays with the new field values, and then FIELDSTORE_FORM will build the 3024 * new tuple value. 3025 * 3026 * Source record is in step's result variable. 3027 */ 3028 void 3029 ExecEvalFieldStoreDeForm(ExprState *state, ExprEvalStep *op, ExprContext *econtext) 3030 { 3031 TupleDesc tupDesc; 3032 3033 /* Lookup tupdesc if first time through or if type changes */ 3034 tupDesc = get_cached_rowtype(op->d.fieldstore.fstore->resulttype, -1, 3035 op->d.fieldstore.rowcache, NULL); 3036 3037 /* Check that current tupdesc doesn't have more fields than we allocated */ 3038 if (unlikely(tupDesc->natts > op->d.fieldstore.ncolumns)) 3039 elog(ERROR, "too many columns in composite type %u", 3040 op->d.fieldstore.fstore->resulttype); 3041 3042 if (*op->resnull) 3043 { 3044 /* Convert null input tuple into an all-nulls row */ 3045 memset(op->d.fieldstore.nulls, true, 3046 op->d.fieldstore.ncolumns * sizeof(bool)); 3047 } 3048 else 3049 { 3050 /* 3051 * heap_deform_tuple needs a HeapTuple not a bare HeapTupleHeader. We 3052 * set all the fields in the struct just in case. 3053 */ 3054 Datum tupDatum = *op->resvalue; 3055 HeapTupleHeader tuphdr; 3056 HeapTupleData tmptup; 3057 3058 tuphdr = DatumGetHeapTupleHeader(tupDatum); 3059 tmptup.t_len = HeapTupleHeaderGetDatumLength(tuphdr); 3060 ItemPointerSetInvalid(&(tmptup.t_self)); 3061 tmptup.t_tableOid = InvalidOid; 3062 tmptup.t_data = tuphdr; 3063 3064 heap_deform_tuple(&tmptup, tupDesc, 3065 op->d.fieldstore.values, 3066 op->d.fieldstore.nulls); 3067 } 3068 } 3069 3070 /* 3071 * Compute the new composite datum after each individual field value of a 3072 * FieldStore expression has been evaluated. 3073 */ 3074 void 3075 ExecEvalFieldStoreForm(ExprState *state, ExprEvalStep *op, ExprContext *econtext) 3076 { 3077 TupleDesc tupDesc; 3078 HeapTuple tuple; 3079 3080 /* Lookup tupdesc (should be valid already) */ 3081 tupDesc = get_cached_rowtype(op->d.fieldstore.fstore->resulttype, -1, 3082 op->d.fieldstore.rowcache, NULL); 3083 3084 tuple = heap_form_tuple(tupDesc, 3085 op->d.fieldstore.values, 3086 op->d.fieldstore.nulls); 3087 3088 *op->resvalue = HeapTupleGetDatum(tuple); 3089 *op->resnull = false; 3090 } 3091 3092 /* 3093 * Process a subscript in a SubscriptingRef expression. 3094 * 3095 * If subscript is NULL, throw error in assignment case, or in fetch case 3096 * set result to NULL and return false (instructing caller to skip the rest 3097 * of the SubscriptingRef sequence). 3098 * 3099 * Subscript expression result is in subscriptvalue/subscriptnull. 3100 * On success, integer subscript value has been saved in upperindex[] or 3101 * lowerindex[] for use later. 3102 */ 3103 bool 3104 ExecEvalSubscriptingRef(ExprState *state, ExprEvalStep *op) 3105 { 3106 SubscriptingRefState *sbsrefstate = op->d.sbsref_subscript.state; 3107 int *indexes; 3108 int off; 3109 3110 /* If any index expr yields NULL, result is NULL or error */ 3111 if (sbsrefstate->subscriptnull) 3112 { 3113 if (sbsrefstate->isassignment) 3114 ereport(ERROR, 3115 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), 3116 errmsg("array subscript in assignment must not be null"))); 3117 *op->resnull = true; 3118 return false; 3119 } 3120 3121 /* Convert datum to int, save in appropriate place */ 3122 if (op->d.sbsref_subscript.isupper) 3123 indexes = sbsrefstate->upperindex; 3124 else 3125 indexes = sbsrefstate->lowerindex; 3126 off = op->d.sbsref_subscript.off; 3127 3128 indexes[off] = DatumGetInt32(sbsrefstate->subscriptvalue); 3129 3130 return true; 3131 } 3132 3133 /* 3134 * Evaluate SubscriptingRef fetch. 3135 * 3136 * Source container is in step's result variable. 3137 */ 3138 void 3139 ExecEvalSubscriptingRefFetch(ExprState *state, ExprEvalStep *op) 3140 { 3141 SubscriptingRefState *sbsrefstate = op->d.sbsref.state; 3142 3143 /* Should not get here if source container (or any subscript) is null */ 3144 Assert(!(*op->resnull)); 3145 3146 if (sbsrefstate->numlower == 0) 3147 { 3148 /* Scalar case */ 3149 *op->resvalue = array_get_element(*op->resvalue, 3150 sbsrefstate->numupper, 3151 sbsrefstate->upperindex, 3152 sbsrefstate->refattrlength, 3153 sbsrefstate->refelemlength, 3154 sbsrefstate->refelembyval, 3155 sbsrefstate->refelemalign, 3156 op->resnull); 3157 } 3158 else 3159 { 3160 /* Slice case */ 3161 *op->resvalue = array_get_slice(*op->resvalue, 3162 sbsrefstate->numupper, 3163 sbsrefstate->upperindex, 3164 sbsrefstate->lowerindex, 3165 sbsrefstate->upperprovided, 3166 sbsrefstate->lowerprovided, 3167 sbsrefstate->refattrlength, 3168 sbsrefstate->refelemlength, 3169 sbsrefstate->refelembyval, 3170 sbsrefstate->refelemalign); 3171 } 3172 } 3173 3174 /* 3175 * Compute old container element/slice value for a SubscriptingRef assignment 3176 * expression. Will only be generated if the new-value subexpression 3177 * contains SubscriptingRef or FieldStore. The value is stored into the 3178 * SubscriptingRefState's prevvalue/prevnull fields. 3179 */ 3180 void 3181 ExecEvalSubscriptingRefOld(ExprState *state, ExprEvalStep *op) 3182 { 3183 SubscriptingRefState *sbsrefstate = op->d.sbsref.state; 3184 3185 if (*op->resnull) 3186 { 3187 /* whole array is null, so any element or slice is too */ 3188 sbsrefstate->prevvalue = (Datum) 0; 3189 sbsrefstate->prevnull = true; 3190 } 3191 else if (sbsrefstate->numlower == 0) 3192 { 3193 /* Scalar case */ 3194 sbsrefstate->prevvalue = array_get_element(*op->resvalue, 3195 sbsrefstate->numupper, 3196 sbsrefstate->upperindex, 3197 sbsrefstate->refattrlength, 3198 sbsrefstate->refelemlength, 3199 sbsrefstate->refelembyval, 3200 sbsrefstate->refelemalign, 3201 &sbsrefstate->prevnull); 3202 } 3203 else 3204 { 3205 /* Slice case */ 3206 /* this is currently unreachable */ 3207 sbsrefstate->prevvalue = array_get_slice(*op->resvalue, 3208 sbsrefstate->numupper, 3209 sbsrefstate->upperindex, 3210 sbsrefstate->lowerindex, 3211 sbsrefstate->upperprovided, 3212 sbsrefstate->lowerprovided, 3213 sbsrefstate->refattrlength, 3214 sbsrefstate->refelemlength, 3215 sbsrefstate->refelembyval, 3216 sbsrefstate->refelemalign); 3217 sbsrefstate->prevnull = false; 3218 } 3219 } 3220 3221 /* 3222 * Evaluate SubscriptingRef assignment. 3223 * 3224 * Input container (possibly null) is in result area, replacement value is in 3225 * SubscriptingRefState's replacevalue/replacenull. 3226 */ 3227 void 3228 ExecEvalSubscriptingRefAssign(ExprState *state, ExprEvalStep *op) 3229 { 3230 SubscriptingRefState *sbsrefstate = op->d.sbsref_subscript.state; 3231 3232 /* 3233 * For an assignment to a fixed-length container type, both the original 3234 * container and the value to be assigned into it must be non-NULL, else 3235 * we punt and return the original container. 3236 */ 3237 if (sbsrefstate->refattrlength > 0) 3238 { 3239 if (*op->resnull || sbsrefstate->replacenull) 3240 return; 3241 } 3242 3243 /* 3244 * For assignment to varlena arrays, we handle a NULL original array by 3245 * substituting an empty (zero-dimensional) array; insertion of the new 3246 * element will result in a singleton array value. It does not matter 3247 * whether the new element is NULL. 3248 */ 3249 if (*op->resnull) 3250 { 3251 *op->resvalue = PointerGetDatum(construct_empty_array(sbsrefstate->refelemtype)); 3252 *op->resnull = false; 3253 } 3254 3255 if (sbsrefstate->numlower == 0) 3256 { 3257 /* Scalar case */ 3258 *op->resvalue = array_set_element(*op->resvalue, 3259 sbsrefstate->numupper, 3260 sbsrefstate->upperindex, 3261 sbsrefstate->replacevalue, 3262 sbsrefstate->replacenull, 3263 sbsrefstate->refattrlength, 3264 sbsrefstate->refelemlength, 3265 sbsrefstate->refelembyval, 3266 sbsrefstate->refelemalign); 3267 } 3268 else 3269 { 3270 /* Slice case */ 3271 *op->resvalue = array_set_slice(*op->resvalue, 3272 sbsrefstate->numupper, 3273 sbsrefstate->upperindex, 3274 sbsrefstate->lowerindex, 3275 sbsrefstate->upperprovided, 3276 sbsrefstate->lowerprovided, 3277 sbsrefstate->replacevalue, 3278 sbsrefstate->replacenull, 3279 sbsrefstate->refattrlength, 3280 sbsrefstate->refelemlength, 3281 sbsrefstate->refelembyval, 3282 sbsrefstate->refelemalign); 3283 } 3284 } 3285 3286 /* 3287 * Evaluate a rowtype coercion operation. 3288 * This may require rearranging field positions. 3289 * 3290 * Source record is in step's result variable. 3291 */ 3292 void 3293 ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext) 3294 { 3295 HeapTuple result; 3296 Datum tupDatum; 3297 HeapTupleHeader tuple; 3298 HeapTupleData tmptup; 3299 TupleDesc indesc, 3300 outdesc; 3301 bool changed = false; 3302 3303 /* NULL in -> NULL out */ 3304 if (*op->resnull) 3305 return; 3306 3307 tupDatum = *op->resvalue; 3308 tuple = DatumGetHeapTupleHeader(tupDatum); 3309 3310 /* 3311 * Lookup tupdescs if first time through or if type changes. We'd better 3312 * pin them since type conversion functions could do catalog lookups and 3313 * hence cause cache invalidation. 3314 */ 3315 indesc = get_cached_rowtype(op->d.convert_rowtype.inputtype, -1, 3316 op->d.convert_rowtype.incache, 3317 &changed); 3318 IncrTupleDescRefCount(indesc); 3319 outdesc = get_cached_rowtype(op->d.convert_rowtype.outputtype, -1, 3320 op->d.convert_rowtype.outcache, 3321 &changed); 3322 IncrTupleDescRefCount(outdesc); 3323 3324 /* 3325 * We used to be able to assert that incoming tuples are marked with 3326 * exactly the rowtype of indesc. However, now that ExecEvalWholeRowVar 3327 * might change the tuples' marking to plain RECORD due to inserting 3328 * aliases, we can only make this weak test: 3329 */ 3330 Assert(HeapTupleHeaderGetTypeId(tuple) == indesc->tdtypeid || 3331 HeapTupleHeaderGetTypeId(tuple) == RECORDOID); 3332 3333 /* if first time through, or after change, initialize conversion map */ 3334 if (changed) 3335 { 3336 MemoryContext old_cxt; 3337 3338 /* allocate map in long-lived memory context */ 3339 old_cxt = MemoryContextSwitchTo(econtext->ecxt_per_query_memory); 3340 3341 /* prepare map from old to new attribute numbers */ 3342 op->d.convert_rowtype.map = 3343 convert_tuples_by_name(indesc, outdesc, 3344 gettext_noop("could not convert row type")); 3345 3346 MemoryContextSwitchTo(old_cxt); 3347 } 3348 3349 /* Following steps need a HeapTuple not a bare HeapTupleHeader */ 3350 tmptup.t_len = HeapTupleHeaderGetDatumLength(tuple); 3351 tmptup.t_data = tuple; 3352 3353 if (op->d.convert_rowtype.map != NULL) 3354 { 3355 /* Full conversion with attribute rearrangement needed */ 3356 result = execute_attr_map_tuple(&tmptup, op->d.convert_rowtype.map); 3357 /* Result already has appropriate composite-datum header fields */ 3358 *op->resvalue = HeapTupleGetDatum(result); 3359 } 3360 else 3361 { 3362 /* 3363 * The tuple is physically compatible as-is, but we need to insert the 3364 * destination rowtype OID in its composite-datum header field, so we 3365 * have to copy it anyway. heap_copy_tuple_as_datum() is convenient 3366 * for this since it will both make the physical copy and insert the 3367 * correct composite header fields. Note that we aren't expecting to 3368 * have to flatten any toasted fields: the input was a composite 3369 * datum, so it shouldn't contain any. So heap_copy_tuple_as_datum() 3370 * is overkill here, but its check for external fields is cheap. 3371 */ 3372 *op->resvalue = heap_copy_tuple_as_datum(&tmptup, outdesc); 3373 } 3374 3375 DecrTupleDescRefCount(indesc); 3376 DecrTupleDescRefCount(outdesc); 3377 } 3378 3379 /* 3380 * Evaluate "scalar op ANY/ALL (array)". 3381 * 3382 * Source array is in our result area, scalar arg is already evaluated into 3383 * fcinfo->args[0]. 3384 * 3385 * The operator always yields boolean, and we combine the results across all 3386 * array elements using OR and AND (for ANY and ALL respectively). Of course 3387 * we short-circuit as soon as the result is known. 3388 */ 3389 void 3390 ExecEvalScalarArrayOp(ExprState *state, ExprEvalStep *op) 3391 { 3392 FunctionCallInfo fcinfo = op->d.scalararrayop.fcinfo_data; 3393 bool useOr = op->d.scalararrayop.useOr; 3394 bool strictfunc = op->d.scalararrayop.finfo->fn_strict; 3395 ArrayType *arr; 3396 int nitems; 3397 Datum result; 3398 bool resultnull; 3399 int i; 3400 int16 typlen; 3401 bool typbyval; 3402 char typalign; 3403 char *s; 3404 bits8 *bitmap; 3405 int bitmask; 3406 3407 /* 3408 * If the array is NULL then we return NULL --- it's not very meaningful 3409 * to do anything else, even if the operator isn't strict. 3410 */ 3411 if (*op->resnull) 3412 return; 3413 3414 /* Else okay to fetch and detoast the array */ 3415 arr = DatumGetArrayTypeP(*op->resvalue); 3416 3417 /* 3418 * If the array is empty, we return either FALSE or TRUE per the useOr 3419 * flag. This is correct even if the scalar is NULL; since we would 3420 * evaluate the operator zero times, it matters not whether it would want 3421 * to return NULL. 3422 */ 3423 nitems = ArrayGetNItems(ARR_NDIM(arr), ARR_DIMS(arr)); 3424 if (nitems <= 0) 3425 { 3426 *op->resvalue = BoolGetDatum(!useOr); 3427 *op->resnull = false; 3428 return; 3429 } 3430 3431 /* 3432 * If the scalar is NULL, and the function is strict, return NULL; no 3433 * point in iterating the loop. 3434 */ 3435 if (fcinfo->args[0].isnull && strictfunc) 3436 { 3437 *op->resnull = true; 3438 return; 3439 } 3440 3441 /* 3442 * We arrange to look up info about the element type only once per series 3443 * of calls, assuming the element type doesn't change underneath us. 3444 */ 3445 if (op->d.scalararrayop.element_type != ARR_ELEMTYPE(arr)) 3446 { 3447 get_typlenbyvalalign(ARR_ELEMTYPE(arr), 3448 &op->d.scalararrayop.typlen, 3449 &op->d.scalararrayop.typbyval, 3450 &op->d.scalararrayop.typalign); 3451 op->d.scalararrayop.element_type = ARR_ELEMTYPE(arr); 3452 } 3453 3454 typlen = op->d.scalararrayop.typlen; 3455 typbyval = op->d.scalararrayop.typbyval; 3456 typalign = op->d.scalararrayop.typalign; 3457 3458 /* Initialize result appropriately depending on useOr */ 3459 result = BoolGetDatum(!useOr); 3460 resultnull = false; 3461 3462 /* Loop over the array elements */ 3463 s = (char *) ARR_DATA_PTR(arr); 3464 bitmap = ARR_NULLBITMAP(arr); 3465 bitmask = 1; 3466 3467 for (i = 0; i < nitems; i++) 3468 { 3469 Datum elt; 3470 Datum thisresult; 3471 3472 /* Get array element, checking for NULL */ 3473 if (bitmap && (*bitmap & bitmask) == 0) 3474 { 3475 fcinfo->args[1].value = (Datum) 0; 3476 fcinfo->args[1].isnull = true; 3477 } 3478 else 3479 { 3480 elt = fetch_att(s, typbyval, typlen); 3481 s = att_addlength_pointer(s, typlen, s); 3482 s = (char *) att_align_nominal(s, typalign); 3483 fcinfo->args[1].value = elt; 3484 fcinfo->args[1].isnull = false; 3485 } 3486 3487 /* Call comparison function */ 3488 if (fcinfo->args[1].isnull && strictfunc) 3489 { 3490 fcinfo->isnull = true; 3491 thisresult = (Datum) 0; 3492 } 3493 else 3494 { 3495 fcinfo->isnull = false; 3496 thisresult = op->d.scalararrayop.fn_addr(fcinfo); 3497 } 3498 3499 /* Combine results per OR or AND semantics */ 3500 if (fcinfo->isnull) 3501 resultnull = true; 3502 else if (useOr) 3503 { 3504 if (DatumGetBool(thisresult)) 3505 { 3506 result = BoolGetDatum(true); 3507 resultnull = false; 3508 break; /* needn't look at any more elements */ 3509 } 3510 } 3511 else 3512 { 3513 if (!DatumGetBool(thisresult)) 3514 { 3515 result = BoolGetDatum(false); 3516 resultnull = false; 3517 break; /* needn't look at any more elements */ 3518 } 3519 } 3520 3521 /* advance bitmap pointer if any */ 3522 if (bitmap) 3523 { 3524 bitmask <<= 1; 3525 if (bitmask == 0x100) 3526 { 3527 bitmap++; 3528 bitmask = 1; 3529 } 3530 } 3531 } 3532 3533 *op->resvalue = result; 3534 *op->resnull = resultnull; 3535 } 3536 3537 /* 3538 * Evaluate a NOT NULL domain constraint. 3539 */ 3540 void 3541 ExecEvalConstraintNotNull(ExprState *state, ExprEvalStep *op) 3542 { 3543 if (*op->resnull) 3544 ereport(ERROR, 3545 (errcode(ERRCODE_NOT_NULL_VIOLATION), 3546 errmsg("domain %s does not allow null values", 3547 format_type_be(op->d.domaincheck.resulttype)), 3548 errdatatype(op->d.domaincheck.resulttype))); 3549 } 3550 3551 /* 3552 * Evaluate a CHECK domain constraint. 3553 */ 3554 void 3555 ExecEvalConstraintCheck(ExprState *state, ExprEvalStep *op) 3556 { 3557 if (!*op->d.domaincheck.checknull && 3558 !DatumGetBool(*op->d.domaincheck.checkvalue)) 3559 ereport(ERROR, 3560 (errcode(ERRCODE_CHECK_VIOLATION), 3561 errmsg("value for domain %s violates check constraint \"%s\"", 3562 format_type_be(op->d.domaincheck.resulttype), 3563 op->d.domaincheck.constraintname), 3564 errdomainconstraint(op->d.domaincheck.resulttype, 3565 op->d.domaincheck.constraintname))); 3566 } 3567 3568 /* 3569 * Evaluate the various forms of XmlExpr. 3570 * 3571 * Arguments have been evaluated into named_argvalue/named_argnull 3572 * and/or argvalue/argnull arrays. 3573 */ 3574 void 3575 ExecEvalXmlExpr(ExprState *state, ExprEvalStep *op) 3576 { 3577 XmlExpr *xexpr = op->d.xmlexpr.xexpr; 3578 Datum value; 3579 int i; 3580 3581 *op->resnull = true; /* until we get a result */ 3582 *op->resvalue = (Datum) 0; 3583 3584 switch (xexpr->op) 3585 { 3586 case IS_XMLCONCAT: 3587 { 3588 Datum *argvalue = op->d.xmlexpr.argvalue; 3589 bool *argnull = op->d.xmlexpr.argnull; 3590 List *values = NIL; 3591 3592 for (i = 0; i < list_length(xexpr->args); i++) 3593 { 3594 if (!argnull[i]) 3595 values = lappend(values, DatumGetPointer(argvalue[i])); 3596 } 3597 3598 if (values != NIL) 3599 { 3600 *op->resvalue = PointerGetDatum(xmlconcat(values)); 3601 *op->resnull = false; 3602 } 3603 } 3604 break; 3605 3606 case IS_XMLFOREST: 3607 { 3608 Datum *argvalue = op->d.xmlexpr.named_argvalue; 3609 bool *argnull = op->d.xmlexpr.named_argnull; 3610 StringInfoData buf; 3611 ListCell *lc; 3612 ListCell *lc2; 3613 3614 initStringInfo(&buf); 3615 3616 i = 0; 3617 forboth(lc, xexpr->named_args, lc2, xexpr->arg_names) 3618 { 3619 Expr *e = (Expr *) lfirst(lc); 3620 char *argname = strVal(lfirst(lc2)); 3621 3622 if (!argnull[i]) 3623 { 3624 value = argvalue[i]; 3625 appendStringInfo(&buf, "<%s>%s</%s>", 3626 argname, 3627 map_sql_value_to_xml_value(value, 3628 exprType((Node *) e), true), 3629 argname); 3630 *op->resnull = false; 3631 } 3632 i++; 3633 } 3634 3635 if (!*op->resnull) 3636 { 3637 text *result; 3638 3639 result = cstring_to_text_with_len(buf.data, buf.len); 3640 *op->resvalue = PointerGetDatum(result); 3641 } 3642 3643 pfree(buf.data); 3644 } 3645 break; 3646 3647 case IS_XMLELEMENT: 3648 *op->resvalue = PointerGetDatum(xmlelement(xexpr, 3649 op->d.xmlexpr.named_argvalue, 3650 op->d.xmlexpr.named_argnull, 3651 op->d.xmlexpr.argvalue, 3652 op->d.xmlexpr.argnull)); 3653 *op->resnull = false; 3654 break; 3655 3656 case IS_XMLPARSE: 3657 { 3658 Datum *argvalue = op->d.xmlexpr.argvalue; 3659 bool *argnull = op->d.xmlexpr.argnull; 3660 text *data; 3661 bool preserve_whitespace; 3662 3663 /* arguments are known to be text, bool */ 3664 Assert(list_length(xexpr->args) == 2); 3665 3666 if (argnull[0]) 3667 return; 3668 value = argvalue[0]; 3669 data = DatumGetTextPP(value); 3670 3671 if (argnull[1]) /* probably can't happen */ 3672 return; 3673 value = argvalue[1]; 3674 preserve_whitespace = DatumGetBool(value); 3675 3676 *op->resvalue = PointerGetDatum(xmlparse(data, 3677 xexpr->xmloption, 3678 preserve_whitespace)); 3679 *op->resnull = false; 3680 } 3681 break; 3682 3683 case IS_XMLPI: 3684 { 3685 text *arg; 3686 bool isnull; 3687 3688 /* optional argument is known to be text */ 3689 Assert(list_length(xexpr->args) <= 1); 3690 3691 if (xexpr->args) 3692 { 3693 isnull = op->d.xmlexpr.argnull[0]; 3694 if (isnull) 3695 arg = NULL; 3696 else 3697 arg = DatumGetTextPP(op->d.xmlexpr.argvalue[0]); 3698 } 3699 else 3700 { 3701 arg = NULL; 3702 isnull = false; 3703 } 3704 3705 *op->resvalue = PointerGetDatum(xmlpi(xexpr->name, 3706 arg, 3707 isnull, 3708 op->resnull)); 3709 } 3710 break; 3711 3712 case IS_XMLROOT: 3713 { 3714 Datum *argvalue = op->d.xmlexpr.argvalue; 3715 bool *argnull = op->d.xmlexpr.argnull; 3716 xmltype *data; 3717 text *version; 3718 int standalone; 3719 3720 /* arguments are known to be xml, text, int */ 3721 Assert(list_length(xexpr->args) == 3); 3722 3723 if (argnull[0]) 3724 return; 3725 data = DatumGetXmlP(argvalue[0]); 3726 3727 if (argnull[1]) 3728 version = NULL; 3729 else 3730 version = DatumGetTextPP(argvalue[1]); 3731 3732 Assert(!argnull[2]); /* always present */ 3733 standalone = DatumGetInt32(argvalue[2]); 3734 3735 *op->resvalue = PointerGetDatum(xmlroot(data, 3736 version, 3737 standalone)); 3738 *op->resnull = false; 3739 } 3740 break; 3741 3742 case IS_XMLSERIALIZE: 3743 { 3744 Datum *argvalue = op->d.xmlexpr.argvalue; 3745 bool *argnull = op->d.xmlexpr.argnull; 3746 3747 /* argument type is known to be xml */ 3748 Assert(list_length(xexpr->args) == 1); 3749 3750 if (argnull[0]) 3751 return; 3752 value = argvalue[0]; 3753 3754 *op->resvalue = PointerGetDatum( 3755 xmltotext_with_xmloption(DatumGetXmlP(value), 3756 xexpr->xmloption)); 3757 *op->resnull = false; 3758 } 3759 break; 3760 3761 case IS_DOCUMENT: 3762 { 3763 Datum *argvalue = op->d.xmlexpr.argvalue; 3764 bool *argnull = op->d.xmlexpr.argnull; 3765 3766 /* optional argument is known to be xml */ 3767 Assert(list_length(xexpr->args) == 1); 3768 3769 if (argnull[0]) 3770 return; 3771 value = argvalue[0]; 3772 3773 *op->resvalue = 3774 BoolGetDatum(xml_is_document(DatumGetXmlP(value))); 3775 *op->resnull = false; 3776 } 3777 break; 3778 3779 default: 3780 elog(ERROR, "unrecognized XML operation"); 3781 break; 3782 } 3783 } 3784 3785 /* 3786 * ExecEvalGroupingFunc 3787 * 3788 * Computes a bitmask with a bit for each (unevaluated) argument expression 3789 * (rightmost arg is least significant bit). 3790 * 3791 * A bit is set if the corresponding expression is NOT part of the set of 3792 * grouping expressions in the current grouping set. 3793 */ 3794 void 3795 ExecEvalGroupingFunc(ExprState *state, ExprEvalStep *op) 3796 { 3797 int result = 0; 3798 Bitmapset *grouped_cols = op->d.grouping_func.parent->grouped_cols; 3799 ListCell *lc; 3800 3801 foreach(lc, op->d.grouping_func.clauses) 3802 { 3803 int attnum = lfirst_int(lc); 3804 3805 result <<= 1; 3806 3807 if (!bms_is_member(attnum, grouped_cols)) 3808 result |= 1; 3809 } 3810 3811 *op->resvalue = Int32GetDatum(result); 3812 *op->resnull = false; 3813 } 3814 3815 /* 3816 * Hand off evaluation of a subplan to nodeSubplan.c 3817 */ 3818 void 3819 ExecEvalSubPlan(ExprState *state, ExprEvalStep *op, ExprContext *econtext) 3820 { 3821 SubPlanState *sstate = op->d.subplan.sstate; 3822 3823 /* could potentially be nested, so make sure there's enough stack */ 3824 check_stack_depth(); 3825 3826 *op->resvalue = ExecSubPlan(sstate, econtext, op->resnull); 3827 } 3828 3829 /* 3830 * Hand off evaluation of an alternative subplan to nodeSubplan.c 3831 */ 3832 void 3833 ExecEvalAlternativeSubPlan(ExprState *state, ExprEvalStep *op, ExprContext *econtext) 3834 { 3835 AlternativeSubPlanState *asstate = op->d.alternative_subplan.asstate; 3836 3837 /* could potentially be nested, so make sure there's enough stack */ 3838 check_stack_depth(); 3839 3840 *op->resvalue = ExecAlternativeSubPlan(asstate, econtext, op->resnull); 3841 } 3842 3843 /* 3844 * Evaluate a wholerow Var expression. 3845 * 3846 * Returns a Datum whose value is the value of a whole-row range variable 3847 * with respect to given expression context. 3848 */ 3849 void 3850 ExecEvalWholeRowVar(ExprState *state, ExprEvalStep *op, ExprContext *econtext) 3851 { 3852 Var *variable = op->d.wholerow.var; 3853 TupleTableSlot *slot; 3854 TupleDesc output_tupdesc; 3855 MemoryContext oldcontext; 3856 HeapTupleHeader dtuple; 3857 HeapTuple tuple; 3858 3859 /* This was checked by ExecInitExpr */ 3860 Assert(variable->varattno == InvalidAttrNumber); 3861 3862 /* Get the input slot we want */ 3863 switch (variable->varno) 3864 { 3865 case INNER_VAR: 3866 /* get the tuple from the inner node */ 3867 slot = econtext->ecxt_innertuple; 3868 break; 3869 3870 case OUTER_VAR: 3871 /* get the tuple from the outer node */ 3872 slot = econtext->ecxt_outertuple; 3873 break; 3874 3875 /* INDEX_VAR is handled by default case */ 3876 3877 default: 3878 /* get the tuple from the relation being scanned */ 3879 slot = econtext->ecxt_scantuple; 3880 break; 3881 } 3882 3883 /* Apply the junkfilter if any */ 3884 if (op->d.wholerow.junkFilter != NULL) 3885 slot = ExecFilterJunk(op->d.wholerow.junkFilter, slot); 3886 3887 /* 3888 * If first time through, obtain tuple descriptor and check compatibility. 3889 * 3890 * XXX: It'd be great if this could be moved to the expression 3891 * initialization phase, but due to using slots that's currently not 3892 * feasible. 3893 */ 3894 if (op->d.wholerow.first) 3895 { 3896 /* optimistically assume we don't need slow path */ 3897 op->d.wholerow.slow = false; 3898 3899 /* 3900 * If the Var identifies a named composite type, we must check that 3901 * the actual tuple type is compatible with it. 3902 */ 3903 if (variable->vartype != RECORDOID) 3904 { 3905 TupleDesc var_tupdesc; 3906 TupleDesc slot_tupdesc; 3907 int i; 3908 3909 /* 3910 * We really only care about numbers of attributes and data types. 3911 * Also, we can ignore type mismatch on columns that are dropped 3912 * in the destination type, so long as (1) the physical storage 3913 * matches or (2) the actual column value is NULL. Case (1) is 3914 * helpful in some cases involving out-of-date cached plans, while 3915 * case (2) is expected behavior in situations such as an INSERT 3916 * into a table with dropped columns (the planner typically 3917 * generates an INT4 NULL regardless of the dropped column type). 3918 * If we find a dropped column and cannot verify that case (1) 3919 * holds, we have to use the slow path to check (2) for each row. 3920 * 3921 * If vartype is a domain over composite, just look through that 3922 * to the base composite type. 3923 */ 3924 var_tupdesc = lookup_rowtype_tupdesc_domain(variable->vartype, 3925 -1, false); 3926 3927 slot_tupdesc = slot->tts_tupleDescriptor; 3928 3929 if (var_tupdesc->natts != slot_tupdesc->natts) 3930 ereport(ERROR, 3931 (errcode(ERRCODE_DATATYPE_MISMATCH), 3932 errmsg("table row type and query-specified row type do not match"), 3933 errdetail_plural("Table row contains %d attribute, but query expects %d.", 3934 "Table row contains %d attributes, but query expects %d.", 3935 slot_tupdesc->natts, 3936 slot_tupdesc->natts, 3937 var_tupdesc->natts))); 3938 3939 for (i = 0; i < var_tupdesc->natts; i++) 3940 { 3941 Form_pg_attribute vattr = TupleDescAttr(var_tupdesc, i); 3942 Form_pg_attribute sattr = TupleDescAttr(slot_tupdesc, i); 3943 3944 if (vattr->atttypid == sattr->atttypid) 3945 continue; /* no worries */ 3946 if (!vattr->attisdropped) 3947 ereport(ERROR, 3948 (errcode(ERRCODE_DATATYPE_MISMATCH), 3949 errmsg("table row type and query-specified row type do not match"), 3950 errdetail("Table has type %s at ordinal position %d, but query expects %s.", 3951 format_type_be(sattr->atttypid), 3952 i + 1, 3953 format_type_be(vattr->atttypid)))); 3954 3955 if (vattr->attlen != sattr->attlen || 3956 vattr->attalign != sattr->attalign) 3957 op->d.wholerow.slow = true; /* need to check for nulls */ 3958 } 3959 3960 /* 3961 * Use the variable's declared rowtype as the descriptor for the 3962 * output values, modulo possibly assigning new column names 3963 * below. In particular, we *must* absorb any attisdropped 3964 * markings. 3965 */ 3966 oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory); 3967 output_tupdesc = CreateTupleDescCopy(var_tupdesc); 3968 MemoryContextSwitchTo(oldcontext); 3969 3970 ReleaseTupleDesc(var_tupdesc); 3971 } 3972 else 3973 { 3974 /* 3975 * In the RECORD case, we use the input slot's rowtype as the 3976 * descriptor for the output values, modulo possibly assigning new 3977 * column names below. 3978 */ 3979 oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory); 3980 output_tupdesc = CreateTupleDescCopy(slot->tts_tupleDescriptor); 3981 MemoryContextSwitchTo(oldcontext); 3982 } 3983 3984 /* 3985 * Construct a tuple descriptor for the composite values we'll 3986 * produce, and make sure its record type is "blessed". The main 3987 * reason to do this is to be sure that operations such as 3988 * row_to_json() will see the desired column names when they look up 3989 * the descriptor from the type information embedded in the composite 3990 * values. 3991 * 3992 * We already got the correct physical datatype info above, but now we 3993 * should try to find the source RTE and adopt its column aliases, in 3994 * case they are different from the original rowtype's names. For 3995 * example, in "SELECT foo(t) FROM tab t(x,y)", the first two columns 3996 * in the composite output should be named "x" and "y" regardless of 3997 * tab's column names. 3998 * 3999 * If we can't locate the RTE, assume the column names we've got are 4000 * OK. (As of this writing, the only cases where we can't locate the 4001 * RTE are in execution of trigger WHEN clauses, and then the Var will 4002 * have the trigger's relation's rowtype, so its names are fine.) 4003 * Also, if the creator of the RTE didn't bother to fill in an eref 4004 * field, assume our column names are OK. (This happens in COPY, and 4005 * perhaps other places.) 4006 */ 4007 if (econtext->ecxt_estate && 4008 variable->varno <= econtext->ecxt_estate->es_range_table_size) 4009 { 4010 RangeTblEntry *rte = exec_rt_fetch(variable->varno, 4011 econtext->ecxt_estate); 4012 4013 if (rte->eref) 4014 ExecTypeSetColNames(output_tupdesc, rte->eref->colnames); 4015 } 4016 4017 /* Bless the tupdesc if needed, and save it in the execution state */ 4018 op->d.wholerow.tupdesc = BlessTupleDesc(output_tupdesc); 4019 4020 op->d.wholerow.first = false; 4021 } 4022 4023 /* 4024 * Make sure all columns of the slot are accessible in the slot's 4025 * Datum/isnull arrays. 4026 */ 4027 slot_getallattrs(slot); 4028 4029 if (op->d.wholerow.slow) 4030 { 4031 /* Check to see if any dropped attributes are non-null */ 4032 TupleDesc tupleDesc = slot->tts_tupleDescriptor; 4033 TupleDesc var_tupdesc = op->d.wholerow.tupdesc; 4034 int i; 4035 4036 Assert(var_tupdesc->natts == tupleDesc->natts); 4037 4038 for (i = 0; i < var_tupdesc->natts; i++) 4039 { 4040 Form_pg_attribute vattr = TupleDescAttr(var_tupdesc, i); 4041 Form_pg_attribute sattr = TupleDescAttr(tupleDesc, i); 4042 4043 if (!vattr->attisdropped) 4044 continue; /* already checked non-dropped cols */ 4045 if (slot->tts_isnull[i]) 4046 continue; /* null is always okay */ 4047 if (vattr->attlen != sattr->attlen || 4048 vattr->attalign != sattr->attalign) 4049 ereport(ERROR, 4050 (errcode(ERRCODE_DATATYPE_MISMATCH), 4051 errmsg("table row type and query-specified row type do not match"), 4052 errdetail("Physical storage mismatch on dropped attribute at ordinal position %d.", 4053 i + 1))); 4054 } 4055 } 4056 4057 /* 4058 * Build a composite datum, making sure any toasted fields get detoasted. 4059 * 4060 * (Note: it is critical that we not change the slot's state here.) 4061 */ 4062 tuple = toast_build_flattened_tuple(slot->tts_tupleDescriptor, 4063 slot->tts_values, 4064 slot->tts_isnull); 4065 dtuple = tuple->t_data; 4066 4067 /* 4068 * Label the datum with the composite type info we identified before. 4069 * 4070 * (Note: we could skip doing this by passing op->d.wholerow.tupdesc to 4071 * the tuple build step; but that seems a tad risky so let's not.) 4072 */ 4073 HeapTupleHeaderSetTypeId(dtuple, op->d.wholerow.tupdesc->tdtypeid); 4074 HeapTupleHeaderSetTypMod(dtuple, op->d.wholerow.tupdesc->tdtypmod); 4075 4076 *op->resvalue = PointerGetDatum(dtuple); 4077 *op->resnull = false; 4078 } 4079 4080 void 4081 ExecEvalSysVar(ExprState *state, ExprEvalStep *op, ExprContext *econtext, 4082 TupleTableSlot *slot) 4083 { 4084 Datum d; 4085 4086 /* slot_getsysattr has sufficient defenses against bad attnums */ 4087 d = slot_getsysattr(slot, 4088 op->d.var.attnum, 4089 op->resnull); 4090 *op->resvalue = d; 4091 /* this ought to be unreachable, but it's cheap enough to check */ 4092 if (unlikely(*op->resnull)) 4093 elog(ERROR, "failed to fetch attribute from slot"); 4094 } 4095 4096 /* 4097 * Transition value has not been initialized. This is the first non-NULL input 4098 * value for a group. We use it as the initial value for transValue. 4099 */ 4100 void 4101 ExecAggInitGroup(AggState *aggstate, AggStatePerTrans pertrans, AggStatePerGroup pergroup) 4102 { 4103 FunctionCallInfo fcinfo = pertrans->transfn_fcinfo; 4104 MemoryContext oldContext; 4105 4106 /* 4107 * We must copy the datum into aggcontext if it is pass-by-ref. We do not 4108 * need to pfree the old transValue, since it's NULL. (We already checked 4109 * that the agg's input type is binary-compatible with its transtype, so 4110 * straight copy here is OK.) 4111 */ 4112 oldContext = MemoryContextSwitchTo( 4113 aggstate->curaggcontext->ecxt_per_tuple_memory); 4114 pergroup->transValue = datumCopy(fcinfo->args[1].value, 4115 pertrans->transtypeByVal, 4116 pertrans->transtypeLen); 4117 pergroup->transValueIsNull = false; 4118 pergroup->noTransValue = false; 4119 MemoryContextSwitchTo(oldContext); 4120 } 4121 4122 /* 4123 * Ensure that the current transition value is a child of the aggcontext, 4124 * rather than the per-tuple context. 4125 * 4126 * NB: This can change the current memory context. 4127 */ 4128 Datum 4129 ExecAggTransReparent(AggState *aggstate, AggStatePerTrans pertrans, 4130 Datum newValue, bool newValueIsNull, 4131 Datum oldValue, bool oldValueIsNull) 4132 { 4133 Assert(newValue != oldValue); 4134 4135 if (!newValueIsNull) 4136 { 4137 MemoryContextSwitchTo(aggstate->curaggcontext->ecxt_per_tuple_memory); 4138 if (DatumIsReadWriteExpandedObject(newValue, 4139 false, 4140 pertrans->transtypeLen) && 4141 MemoryContextGetParent(DatumGetEOHP(newValue)->eoh_context) == CurrentMemoryContext) 4142 /* do nothing */ ; 4143 else 4144 newValue = datumCopy(newValue, 4145 pertrans->transtypeByVal, 4146 pertrans->transtypeLen); 4147 } 4148 else 4149 { 4150 /* 4151 * Ensure that AggStatePerGroup->transValue ends up being 0, so 4152 * callers can safely compare newValue/oldValue without having to 4153 * check their respective nullness. 4154 */ 4155 newValue = (Datum) 0; 4156 } 4157 4158 if (!oldValueIsNull) 4159 { 4160 if (DatumIsReadWriteExpandedObject(oldValue, 4161 false, 4162 pertrans->transtypeLen)) 4163 DeleteExpandedObject(oldValue); 4164 else 4165 pfree(DatumGetPointer(oldValue)); 4166 } 4167 4168 return newValue; 4169 } 4170 4171 /* 4172 * Invoke ordered transition function, with a datum argument. 4173 */ 4174 void 4175 ExecEvalAggOrderedTransDatum(ExprState *state, ExprEvalStep *op, 4176 ExprContext *econtext) 4177 { 4178 AggStatePerTrans pertrans = op->d.agg_trans.pertrans; 4179 int setno = op->d.agg_trans.setno; 4180 4181 tuplesort_putdatum(pertrans->sortstates[setno], 4182 *op->resvalue, *op->resnull); 4183 } 4184 4185 /* 4186 * Invoke ordered transition function, with a tuple argument. 4187 */ 4188 void 4189 ExecEvalAggOrderedTransTuple(ExprState *state, ExprEvalStep *op, 4190 ExprContext *econtext) 4191 { 4192 AggStatePerTrans pertrans = op->d.agg_trans.pertrans; 4193 int setno = op->d.agg_trans.setno; 4194 4195 ExecClearTuple(pertrans->sortslot); 4196 pertrans->sortslot->tts_nvalid = pertrans->numInputs; 4197 ExecStoreVirtualTuple(pertrans->sortslot); 4198 tuplesort_puttupleslot(pertrans->sortstates[setno], pertrans->sortslot); 4199 } 4200