src/backend/executor/execExprInterp.c - Coverage Report

← Back to Overview

# src/backend/executor/execExprInterp.c

Coverage: 80/88 lines (90.9%)
Total Lines
88
modified
Covered
80
90.9%
Uncovered
8
9.1%
Keyboard navigation
ExecInterpExpr() lines 472-2311
Modified Lines Coverage: 8/8 lines (100.0%)

Line | Hits | Source | Commit
--- | --- | --- | ---
472 | - | ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull) | -
473 | - | { | -
474 | - | ExprEvalStep *op; | -
475 | - | TupleTableSlot *resultslot; | -
476 | - | TupleTableSlot *innerslot; | -
477 | - | TupleTableSlot *outerslot; | -
478 | - | TupleTableSlot *scanslot; | -
479 | - | TupleTableSlot *oldslot; | -
480 | - | TupleTableSlot *newslot; | -
481 | - |  | -
482 | - | /* | -
483 | - | * This array has to be in the same order as enum ExprEvalOp. | -
484 | - | */ | -
485 | - | #if defined(EEO_USE_COMPUTED_GOTO) | -
486 | - | static const void *const dispatch_table[] = { | -
487 | - | &&CASE_EEOP_DONE_RETURN, | -
488 | - | &&CASE_EEOP_DONE_NO_RETURN, | -
489 | - | &&CASE_EEOP_INNER_FETCHSOME, | -
490 | - | &&CASE_EEOP_OUTER_FETCHSOME, | -
491 | - | &&CASE_EEOP_SCAN_FETCHSOME, | -
492 | - | &&CASE_EEOP_OLD_FETCHSOME, | -
493 | - | &&CASE_EEOP_NEW_FETCHSOME, | -
494 | - | &&CASE_EEOP_INNER_VAR, | -
495 | - | &&CASE_EEOP_OUTER_VAR, | -
496 | - | &&CASE_EEOP_SCAN_VAR, | -
497 | - | &&CASE_EEOP_OLD_VAR, | -
498 | - | &&CASE_EEOP_NEW_VAR, | -
499 | - | &&CASE_EEOP_INNER_SYSVAR, | -
500 | - | &&CASE_EEOP_OUTER_SYSVAR, | -
501 | - | &&CASE_EEOP_SCAN_SYSVAR, | -
502 | - | &&CASE_EEOP_OLD_SYSVAR, | -
503 | - | &&CASE_EEOP_NEW_SYSVAR, | -
504 | - | &&CASE_EEOP_WHOLEROW, | -
505 | - | &&CASE_EEOP_ASSIGN_INNER_VAR, | -
506 | - | &&CASE_EEOP_ASSIGN_OUTER_VAR, | -
507 | - | &&CASE_EEOP_ASSIGN_SCAN_VAR, | -
508 | - | &&CASE_EEOP_ASSIGN_OLD_VAR, | -
509 | - | &&CASE_EEOP_ASSIGN_NEW_VAR, | -
510 | - | &&CASE_EEOP_ASSIGN_TMP, | -
511 | - | &&CASE_EEOP_ASSIGN_TMP_MAKE_RO, | -
512 | - | &&CASE_EEOP_CONST, | -
513 | - | &&CASE_EEOP_FUNCEXPR, | -
514 | - | &&CASE_EEOP_FUNCEXPR_STRICT, | -
515 | - | &&CASE_EEOP_FUNCEXPR_STRICT_1, | -
516 | - | &&CASE_EEOP_FUNCEXPR_STRICT_2, | -
517 | - | &&CASE_EEOP_FUNCEXPR_FUSAGE, | -
518 | - | &&CASE_EEOP_FUNCEXPR_STRICT_FUSAGE, | -
519 | - | &&CASE_EEOP_BOOL_AND_STEP_FIRST, | -
520 | - | &&CASE_EEOP_BOOL_AND_STEP, | -
521 | - | &&CASE_EEOP_BOOL_AND_STEP_LAST, | -
522 | - | &&CASE_EEOP_BOOL_OR_STEP_FIRST, | -
523 | - | &&CASE_EEOP_BOOL_OR_STEP, | -
524 | - | &&CASE_EEOP_BOOL_OR_STEP_LAST, | -
525 | - | &&CASE_EEOP_BOOL_NOT_STEP, | -
526 | - | &&CASE_EEOP_QUAL, | -
527 | - | &&CASE_EEOP_JUMP, | -
528 | - | &&CASE_EEOP_JUMP_IF_NULL, | -
529 | - | &&CASE_EEOP_JUMP_IF_NOT_NULL, | -
530 | - | &&CASE_EEOP_JUMP_IF_NOT_TRUE, | -
531 | - | &&CASE_EEOP_NULLTEST_ISNULL, | -
532 | - | &&CASE_EEOP_NULLTEST_ISNOTNULL, | -
533 | - | &&CASE_EEOP_NULLTEST_ROWISNULL, | -
534 | - | &&CASE_EEOP_NULLTEST_ROWISNOTNULL, | -
535 | - | &&CASE_EEOP_BOOLTEST_IS_TRUE, | -
536 | - | &&CASE_EEOP_BOOLTEST_IS_NOT_TRUE, | -
537 | - | &&CASE_EEOP_BOOLTEST_IS_FALSE, | -
538 | - | &&CASE_EEOP_BOOLTEST_IS_NOT_FALSE, | -
539 | - | &&CASE_EEOP_PARAM_EXEC, | -
540 | - | &&CASE_EEOP_PARAM_EXTERN, | -
541 | - | &&CASE_EEOP_PARAM_CALLBACK, | -
542 | - | &&CASE_EEOP_PARAM_SET, | -
543 | - | &&CASE_EEOP_CASE_TESTVAL, | -
544 | - | &&CASE_EEOP_CASE_TESTVAL_EXT, | -
545 | - | &&CASE_EEOP_MAKE_READONLY, | -
546 | - | &&CASE_EEOP_IOCOERCE, | -
547 | - | &&CASE_EEOP_IOCOERCE_SAFE, | -
548 | - | &&CASE_EEOP_DISTINCT, | -
549 | - | &&CASE_EEOP_NOT_DISTINCT, | -
550 | - | &&CASE_EEOP_NULLIF, | -
551 | - | &&CASE_EEOP_SQLVALUEFUNCTION, | -
552 | - | &&CASE_EEOP_CURRENTOFEXPR, | -
553 | - | &&CASE_EEOP_NEXTVALUEEXPR, | -
554 | - | &&CASE_EEOP_RETURNINGEXPR, | -
555 | - | &&CASE_EEOP_ARRAYEXPR, | -
556 | - | &&CASE_EEOP_ARRAYCOERCE, | -
557 | - | &&CASE_EEOP_ROW, | -
558 | - | &&CASE_EEOP_ROWCOMPARE_STEP, | -
559 | - | &&CASE_EEOP_ROWCOMPARE_FINAL, | -
560 | - | &&CASE_EEOP_MINMAX, | -
561 | - | &&CASE_EEOP_FIELDSELECT, | -
562 | - | &&CASE_EEOP_FIELDSTORE_DEFORM, | -
563 | - | &&CASE_EEOP_FIELDSTORE_FORM, | -
564 | - | &&CASE_EEOP_SBSREF_SUBSCRIPTS, | -
565 | - | &&CASE_EEOP_SBSREF_OLD, | -
566 | - | &&CASE_EEOP_SBSREF_ASSIGN, | -
567 | - | &&CASE_EEOP_SBSREF_FETCH, | -
568 | - | &&CASE_EEOP_DOMAIN_TESTVAL, | -
569 | - | &&CASE_EEOP_DOMAIN_TESTVAL_EXT, | -
570 | - | &&CASE_EEOP_DOMAIN_NOTNULL, | -
571 | - | &&CASE_EEOP_DOMAIN_CHECK, | -
572 | - | &&CASE_EEOP_HASHDATUM_SET_INITVAL, | -
573 | - | &&CASE_EEOP_HASHDATUM_FIRST, | -
574 | - | &&CASE_EEOP_HASHDATUM_FIRST_STRICT, | -
575 | - | &&CASE_EEOP_HASHDATUM_NEXT32, | -
576 | - | &&CASE_EEOP_HASHDATUM_NEXT32_STRICT, | -
577 | - | &&CASE_EEOP_CONVERT_ROWTYPE, | -
578 | - | &&CASE_EEOP_SCALARARRAYOP, | -
579 | - | &&CASE_EEOP_HASHED_SCALARARRAYOP, | -
580 | - | &&CASE_EEOP_XMLEXPR, | -
581 | - | &&CASE_EEOP_JSON_CONSTRUCTOR, | -
582 | - | &&CASE_EEOP_IS_JSON, | -
583 | - | &&CASE_EEOP_JSONEXPR_PATH, | -
584 | - | &&CASE_EEOP_JSONEXPR_COERCION, | -
585 | - | &&CASE_EEOP_JSONEXPR_COERCION_FINISH, | -
586 | - | &&CASE_EEOP_AGGREF, | -
587 | - | &&CASE_EEOP_GROUPING_FUNC, | -
588 | - | &&CASE_EEOP_WINDOW_FUNC, | -
589 | - | &&CASE_EEOP_MERGE_SUPPORT_FUNC, | -
590 | - | &&CASE_EEOP_SUBPLAN, | -
591 | - | &&CASE_EEOP_RPR_NAV_SET, | 24cfb8dRow pattern recognition patch (executor and commands).
592 | - | &&CASE_EEOP_RPR_NAV_RESTORE, | 24cfb8dRow pattern recognition patch (executor and commands).
593 | - | &&CASE_EEOP_AGG_STRICT_DESERIALIZE, | -
594 | - | &&CASE_EEOP_AGG_DESERIALIZE, | -
595 | - | &&CASE_EEOP_AGG_STRICT_INPUT_CHECK_ARGS, | -
596 | - | &&CASE_EEOP_AGG_STRICT_INPUT_CHECK_ARGS_1, | -
597 | - | &&CASE_EEOP_AGG_STRICT_INPUT_CHECK_NULLS, | -
598 | - | &&CASE_EEOP_AGG_PLAIN_PERGROUP_NULLCHECK, | -
599 | - | &&CASE_EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL, | -
600 | - | &&CASE_EEOP_AGG_PLAIN_TRANS_STRICT_BYVAL, | -
601 | - | &&CASE_EEOP_AGG_PLAIN_TRANS_BYVAL, | -
602 | - | &&CASE_EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYREF, | -
603 | - | &&CASE_EEOP_AGG_PLAIN_TRANS_STRICT_BYREF, | -
604 | - | &&CASE_EEOP_AGG_PLAIN_TRANS_BYREF, | -
605 | - | &&CASE_EEOP_AGG_PRESORTED_DISTINCT_SINGLE, | -
606 | - | &&CASE_EEOP_AGG_PRESORTED_DISTINCT_MULTI, | -
607 | - | &&CASE_EEOP_AGG_ORDERED_TRANS_DATUM, | -
608 | - | &&CASE_EEOP_AGG_ORDERED_TRANS_TUPLE, | -
609 | - | &&CASE_EEOP_LAST | -
610 | - | }; | -
611 | - |  | -
612 | - | StaticAssertDecl(lengthof(dispatch_table) == EEOP_LAST + 1, | -
613 | - | "dispatch_table out of whack with ExprEvalOp"); | -
614 | - |  | -
615 | - | if (unlikely(state == NULL)) | -
616 | - | return PointerGetDatum(dispatch_table); | -
617 | - | #else | -
618 | - | Assert(state != NULL); | -
619 | - | #endif /* EEO_USE_COMPUTED_GOTO */ | -
620 | - |  | -
621 | - | /* setup state */ | -
622 | - | op = state->steps; | -
623 | - | resultslot = state->resultslot; | -
624 | - | innerslot = econtext->ecxt_innertuple; | -
625 | - | outerslot = econtext->ecxt_outertuple; | -
626 | - | scanslot = econtext->ecxt_scantuple; | -
627 | - | oldslot = econtext->ecxt_oldtuple; | -
628 | - | newslot = econtext->ecxt_newtuple; | -
629 | - |  | -
630 | - | #if defined(EEO_USE_COMPUTED_GOTO) | -
631 | - | EEO_DISPATCH(); | -
632 | - | #endif | -
633 | - |  | -
634 | - | EEO_SWITCH() | -
635 | - | { | -
636 | - | EEO_CASE(EEOP_DONE_RETURN) | -
637 | - | { | -
638 | - | *isnull = state->resnull; | -
639 | - | return state->resvalue; | -
640 | - | } | -
641 | - |  | -
642 | - | EEO_CASE(EEOP_DONE_NO_RETURN) | -
643 | - | { | -
644 | - | Assert(isnull == NULL); | -
645 | - | return (Datum) 0; | -
646 | - | } | -
647 | - |  | -
648 | - | EEO_CASE(EEOP_INNER_FETCHSOME) | -
649 | - | { | -
650 | - | CheckOpSlotCompatibility(op, innerslot); | -
651 | - |  | -
652 | - | slot_getsomeattrs(innerslot, op->d.fetch.last_var); | -
653 | - |  | -
654 | - | EEO_NEXT(); | -
655 | - | } | -
656 | - |  | -
657 | - | EEO_CASE(EEOP_OUTER_FETCHSOME) | -
658 | - | { | -
659 | - | CheckOpSlotCompatibility(op, outerslot); | -
660 | - |  | -
661 | - | slot_getsomeattrs(outerslot, op->d.fetch.last_var); | -
662 | - |  | -
663 | - | EEO_NEXT(); | -
664 | - | } | -
665 | - |  | -
666 | - | EEO_CASE(EEOP_SCAN_FETCHSOME) | -
667 | - | { | -
668 | - | CheckOpSlotCompatibility(op, scanslot); | -
669 | - |  | -
670 | - | slot_getsomeattrs(scanslot, op->d.fetch.last_var); | -
671 | - |  | -
672 | - | EEO_NEXT(); | -
673 | - | } | -
674 | - |  | -
675 | - | EEO_CASE(EEOP_OLD_FETCHSOME) | -
676 | - | { | -
677 | - | CheckOpSlotCompatibility(op, oldslot); | -
678 | - |  | -
679 | - | slot_getsomeattrs(oldslot, op->d.fetch.last_var); | -
680 | - |  | -
681 | - | EEO_NEXT(); | -
682 | - | } | -
683 | - |  | -
684 | - | EEO_CASE(EEOP_NEW_FETCHSOME) | -
685 | - | { | -
686 | - | CheckOpSlotCompatibility(op, newslot); | -
687 | - |  | -
688 | - | slot_getsomeattrs(newslot, op->d.fetch.last_var); | -
689 | - |  | -
690 | - | EEO_NEXT(); | -
691 | - | } | -
692 | - |  | -
693 | - | EEO_CASE(EEOP_INNER_VAR) | -
694 | - | { | -
695 | - | int attnum = op->d.var.attnum; | -
696 | - |  | -
697 | - | /* | -
698 | - | * Since we already extracted all referenced columns from the | -
699 | - | * tuple with a FETCHSOME step, we can just grab the value | -
700 | - | * directly out of the slot's decomposed-data arrays. But let's | -
701 | - | * have an Assert to check that that did happen. | -
702 | - | */ | -
703 | - | Assert(attnum >= 0 && attnum < innerslot->tts_nvalid); | -
704 | - | *op->resvalue = innerslot->tts_values[attnum]; | -
705 | - | *op->resnull = innerslot->tts_isnull[attnum]; | -
706 | - |  | -
707 | - | EEO_NEXT(); | -
708 | - | } | -
709 | - |  | -
710 | - | EEO_CASE(EEOP_OUTER_VAR) | -
711 | - | { | -
712 | - | int attnum = op->d.var.attnum; | -
713 | - |  | -
714 | - | /* See EEOP_INNER_VAR comments */ | -
715 | - |  | -
716 | - | Assert(attnum >= 0 && attnum < outerslot->tts_nvalid); | -
717 | - | *op->resvalue = outerslot->tts_values[attnum]; | -
718 | - | *op->resnull = outerslot->tts_isnull[attnum]; | -
719 | - |  | -
720 | - | EEO_NEXT(); | -
721 | - | } | -
722 | - |  | -
723 | - | EEO_CASE(EEOP_SCAN_VAR) | -
724 | - | { | -
725 | - | int attnum = op->d.var.attnum; | -
726 | - |  | -
727 | - | /* See EEOP_INNER_VAR comments */ | -
728 | - |  | -
729 | - | Assert(attnum >= 0 && attnum < scanslot->tts_nvalid); | -
730 | - | *op->resvalue = scanslot->tts_values[attnum]; | -
731 | - | *op->resnull = scanslot->tts_isnull[attnum]; | -
732 | - |  | -
733 | - | EEO_NEXT(); | -
734 | - | } | -
735 | - |  | -
736 | - | EEO_CASE(EEOP_OLD_VAR) | -
737 | - | { | -
738 | - | int attnum = op->d.var.attnum; | -
739 | - |  | -
740 | - | /* See EEOP_INNER_VAR comments */ | -
741 | - |  | -
742 | - | Assert(attnum >= 0 && attnum < oldslot->tts_nvalid); | -
743 | - | *op->resvalue = oldslot->tts_values[attnum]; | -
744 | - | *op->resnull = oldslot->tts_isnull[attnum]; | -
745 | - |  | -
746 | - | EEO_NEXT(); | -
747 | - | } | -
748 | - |  | -
749 | - | EEO_CASE(EEOP_NEW_VAR) | -
750 | - | { | -
751 | - | int attnum = op->d.var.attnum; | -
752 | - |  | -
753 | - | /* See EEOP_INNER_VAR comments */ | -
754 | - |  | -
755 | - | Assert(attnum >= 0 && attnum < newslot->tts_nvalid); | -
756 | - | *op->resvalue = newslot->tts_values[attnum]; | -
757 | - | *op->resnull = newslot->tts_isnull[attnum]; | -
758 | - |  | -
759 | - | EEO_NEXT(); | -
760 | - | } | -
761 | - |  | -
762 | - | EEO_CASE(EEOP_INNER_SYSVAR) | -
763 | - | { | -
764 | - | ExecEvalSysVar(state, op, econtext, innerslot); | -
765 | - | EEO_NEXT(); | -
766 | - | } | -
767 | - |  | -
768 | - | EEO_CASE(EEOP_OUTER_SYSVAR) | -
769 | - | { | -
770 | - | ExecEvalSysVar(state, op, econtext, outerslot); | -
771 | - | EEO_NEXT(); | -
772 | - | } | -
773 | - |  | -
774 | - | EEO_CASE(EEOP_SCAN_SYSVAR) | -
775 | - | { | -
776 | - | ExecEvalSysVar(state, op, econtext, scanslot); | -
777 | - | EEO_NEXT(); | -
778 | - | } | -
779 | - |  | -
780 | - | EEO_CASE(EEOP_OLD_SYSVAR) | -
781 | - | { | -
782 | - | ExecEvalSysVar(state, op, econtext, oldslot); | -
783 | - | EEO_NEXT(); | -
784 | - | } | -
785 | - |  | -
786 | - | EEO_CASE(EEOP_NEW_SYSVAR) | -
787 | - | { | -
788 | - | ExecEvalSysVar(state, op, econtext, newslot); | -
789 | - | EEO_NEXT(); | -
790 | - | } | -
791 | - |  | -
792 | - | EEO_CASE(EEOP_WHOLEROW) | -
793 | - | { | -
794 | - | /* too complex for an inline implementation */ | -
795 | - | ExecEvalWholeRowVar(state, op, econtext); | -
796 | - |  | -
797 | - | EEO_NEXT(); | -
798 | - | } | -
799 | - |  | -
800 | - | EEO_CASE(EEOP_ASSIGN_INNER_VAR) | -
801 | - | { | -
802 | - | int resultnum = op->d.assign_var.resultnum; | -
803 | - | int attnum = op->d.assign_var.attnum; | -
804 | - |  | -
805 | - | /* | -
806 | - | * We do not need CheckVarSlotCompatibility here; that was taken | -
807 | - | * care of at compilation time. But see EEOP_INNER_VAR comments. | -
808 | - | */ | -
809 | - | Assert(attnum >= 0 && attnum < innerslot->tts_nvalid); | -
810 | - | Assert(resultnum >= 0 && resultnum < resultslot->tts_tupleDescriptor->natts); | -
811 | - | resultslot->tts_values[resultnum] = innerslot->tts_values[attnum]; | -
812 | - | resultslot->tts_isnull[resultnum] = innerslot->tts_isnull[attnum]; | -
813 | - |  | -
814 | - | EEO_NEXT(); | -
815 | - | } | -
816 | - |  | -
817 | - | EEO_CASE(EEOP_ASSIGN_OUTER_VAR) | -
818 | - | { | -
819 | - | int resultnum = op->d.assign_var.resultnum; | -
820 | - | int attnum = op->d.assign_var.attnum; | -
821 | - |  | -
822 | - | /* | -
823 | - | * We do not need CheckVarSlotCompatibility here; that was taken | -
824 | - | * care of at compilation time. But see EEOP_INNER_VAR comments. | -
825 | - | */ | -
826 | - | Assert(attnum >= 0 && attnum < outerslot->tts_nvalid); | -
827 | - | Assert(resultnum >= 0 && resultnum < resultslot->tts_tupleDescriptor->natts); | -
828 | - | resultslot->tts_values[resultnum] = outerslot->tts_values[attnum]; | -
829 | - | resultslot->tts_isnull[resultnum] = outerslot->tts_isnull[attnum]; | -
830 | - |  | -
831 | - | EEO_NEXT(); | -
832 | - | } | -
833 | - |  | -
834 | - | EEO_CASE(EEOP_ASSIGN_SCAN_VAR) | -
835 | - | { | -
836 | - | int resultnum = op->d.assign_var.resultnum; | -
837 | - | int attnum = op->d.assign_var.attnum; | -
838 | - |  | -
839 | - | /* | -
840 | - | * We do not need CheckVarSlotCompatibility here; that was taken | -
841 | - | * care of at compilation time. But see EEOP_INNER_VAR comments. | -
842 | - | */ | -
843 | - | Assert(attnum >= 0 && attnum < scanslot->tts_nvalid); | -
844 | - | Assert(resultnum >= 0 && resultnum < resultslot->tts_tupleDescriptor->natts); | -
845 | - | resultslot->tts_values[resultnum] = scanslot->tts_values[attnum]; | -
846 | - | resultslot->tts_isnull[resultnum] = scanslot->tts_isnull[attnum]; | -
847 | - |  | -
848 | - | EEO_NEXT(); | -
849 | - | } | -
850 | - |  | -
851 | - | EEO_CASE(EEOP_ASSIGN_OLD_VAR) | -
852 | - | { | -
853 | - | int resultnum = op->d.assign_var.resultnum; | -
854 | - | int attnum = op->d.assign_var.attnum; | -
855 | - |  | -
856 | - | /* | -
857 | - | * We do not need CheckVarSlotCompatibility here; that was taken | -
858 | - | * care of at compilation time. But see EEOP_INNER_VAR comments. | -
859 | - | */ | -
860 | - | Assert(attnum >= 0 && attnum < oldslot->tts_nvalid); | -
861 | - | Assert(resultnum >= 0 && resultnum < resultslot->tts_tupleDescriptor->natts); | -
862 | - | resultslot->tts_values[resultnum] = oldslot->tts_values[attnum]; | -
863 | - | resultslot->tts_isnull[resultnum] = oldslot->tts_isnull[attnum]; | -
864 | - |  | -
865 | - | EEO_NEXT(); | -
866 | - | } | -
867 | - |  | -
868 | - | EEO_CASE(EEOP_ASSIGN_NEW_VAR) | -
869 | - | { | -
870 | - | int resultnum = op->d.assign_var.resultnum; | -
871 | - | int attnum = op->d.assign_var.attnum; | -
872 | - |  | -
873 | - | /* | -
874 | - | * We do not need CheckVarSlotCompatibility here; that was taken | -
875 | - | * care of at compilation time. But see EEOP_INNER_VAR comments. | -
876 | - | */ | -
877 | - | Assert(attnum >= 0 && attnum < newslot->tts_nvalid); | -
878 | - | Assert(resultnum >= 0 && resultnum < resultslot->tts_tupleDescriptor->natts); | -
879 | - | resultslot->tts_values[resultnum] = newslot->tts_values[attnum]; | -
880 | - | resultslot->tts_isnull[resultnum] = newslot->tts_isnull[attnum]; | -
881 | - |  | -
882 | - | EEO_NEXT(); | -
883 | - | } | -
884 | - |  | -
885 | - | EEO_CASE(EEOP_ASSIGN_TMP) | -
886 | - | { | -
887 | - | int resultnum = op->d.assign_tmp.resultnum; | -
888 | - |  | -
889 | - | Assert(resultnum >= 0 && resultnum < resultslot->tts_tupleDescriptor->natts); | -
890 | - | resultslot->tts_values[resultnum] = state->resvalue; | -
891 | - | resultslot->tts_isnull[resultnum] = state->resnull; | -
892 | - |  | -
893 | - | EEO_NEXT(); | -
894 | - | } | -
895 | - |  | -
896 | - | EEO_CASE(EEOP_ASSIGN_TMP_MAKE_RO) | -
897 | - | { | -
898 | - | int resultnum = op->d.assign_tmp.resultnum; | -
899 | - |  | -
900 | - | Assert(resultnum >= 0 && resultnum < resultslot->tts_tupleDescriptor->natts); | -
901 | - | resultslot->tts_isnull[resultnum] = state->resnull; | -
902 | - | if (!resultslot->tts_isnull[resultnum]) | -
903 | - | resultslot->tts_values[resultnum] = | -
904 | - | MakeExpandedObjectReadOnlyInternal(state->resvalue); | -
905 | - | else | -
906 | - | resultslot->tts_values[resultnum] = state->resvalue; | -
907 | - |  | -
908 | - | EEO_NEXT(); | -
909 | - | } | -
910 | - |  | -
911 | - | EEO_CASE(EEOP_CONST) | -
912 | - | { | -
913 | - | *op->resnull = op->d.constval.isnull; | -
914 | - | *op->resvalue = op->d.constval.value; | -
915 | - |  | -
916 | - | EEO_NEXT(); | -
917 | - | } | -
918 | - |  | -
919 | - | /* | -
920 | - | * Function-call implementations. Arguments have previously been | -
921 | - | * evaluated directly into fcinfo->args. | -
922 | - | * | -
923 | - | * As both STRICT checks and function-usage are noticeable performance | -
924 | - | * wise, and function calls are a very hot-path (they also back | -
925 | - | * operators!), it's worth having so many separate opcodes. | -
926 | - | * | -
927 | - | * Note: the reason for using a temporary variable "d", here and in | -
928 | - | * other places, is that some compilers think "*op->resvalue = f();" | -
929 | - | * requires them to evaluate op->resvalue into a register before | -
930 | - | * calling f(), just in case f() is able to modify op->resvalue | -
931 | - | * somehow. The extra line of code can save a useless register spill | -
932 | - | * and reload across the function call. | -
933 | - | */ | -
934 | - | EEO_CASE(EEOP_FUNCEXPR) | -
935 | - | { | -
936 | - | FunctionCallInfo fcinfo = op->d.func.fcinfo_data; | -
937 | - | Datum d; | -
938 | - |  | -
939 | - | fcinfo->isnull = false; | -
940 | - | d = op->d.func.fn_addr(fcinfo); | -
941 | - | *op->resvalue = d; | -
942 | - | *op->resnull = fcinfo->isnull; | -
943 | - |  | -
944 | - | EEO_NEXT(); | -
945 | - | } | -
946 | - |  | -
947 | - | /* strict function call with more than two arguments */ | -
948 | - | EEO_CASE(EEOP_FUNCEXPR_STRICT) | -
949 | - | { | -
950 | - | FunctionCallInfo fcinfo = op->d.func.fcinfo_data; | -
951 | - | NullableDatum *args = fcinfo->args; | -
952 | - | int nargs = op->d.func.nargs; | -
953 | - | Datum d; | -
954 | - |  | -
955 | - | Assert(nargs > 2); | -
956 | - |  | -
957 | - | /* strict function, so check for NULL args */ | -
958 | - | for (int argno = 0; argno < nargs; argno++) | -
959 | - | { | -
960 | - | if (args[argno].isnull) | -
961 | - | { | -
962 | - | *op->resnull = true; | -
963 | - | goto strictfail; | -
964 | - | } | -
965 | - | } | -
966 | - | fcinfo->isnull = false; | -
967 | - | d = op->d.func.fn_addr(fcinfo); | -
968 | - | *op->resvalue = d; | -
969 | - | *op->resnull = fcinfo->isnull; | -
970 | - |  | -
971 | - | strictfail: | -
972 | - | EEO_NEXT(); | -
973 | - | } | -
974 | - |  | -
975 | - | /* strict function call with one argument */ | -
976 | - | EEO_CASE(EEOP_FUNCEXPR_STRICT_1) | -
977 | - | { | -
978 | - | FunctionCallInfo fcinfo = op->d.func.fcinfo_data; | -
979 | - | NullableDatum *args = fcinfo->args; | -
980 | - |  | -
981 | - | Assert(op->d.func.nargs == 1); | -
982 | - |  | -
983 | - | /* strict function, so check for NULL args */ | -
984 | - | if (args[0].isnull) | -
985 | - | *op->resnull = true; | -
986 | - | else | -
987 | - | { | -
988 | - | Datum d; | -
989 | - |  | -
990 | - | fcinfo->isnull = false; | -
991 | - | d = op->d.func.fn_addr(fcinfo); | -
992 | - | *op->resvalue = d; | -
993 | - | *op->resnull = fcinfo->isnull; | -
994 | - | } | -
995 | - |  | -
996 | - | EEO_NEXT(); | -
997 | - | } | -
998 | - |  | -
999 | - | /* strict function call with two arguments */ | -
1000 | - | EEO_CASE(EEOP_FUNCEXPR_STRICT_2) | -
1001 | - | { | -
1002 | - | FunctionCallInfo fcinfo = op->d.func.fcinfo_data; | -
1003 | - | NullableDatum *args = fcinfo->args; | -
1004 | - |  | -
1005 | - | Assert(op->d.func.nargs == 2); | -
1006 | - |  | -
1007 | - | /* strict function, so check for NULL args */ | -
1008 | - | if (args[0].isnull || args[1].isnull) | -
1009 | - | *op->resnull = true; | -
1010 | - | else | -
1011 | - | { | -
1012 | - | Datum d; | -
1013 | - |  | -
1014 | - | fcinfo->isnull = false; | -
1015 | - | d = op->d.func.fn_addr(fcinfo); | -
1016 | - | *op->resvalue = d; | -
1017 | - | *op->resnull = fcinfo->isnull; | -
1018 | - | } | -
1019 | - |  | -
1020 | - | EEO_NEXT(); | -
1021 | - | } | -
1022 | - |  | -
1023 | - | EEO_CASE(EEOP_FUNCEXPR_FUSAGE) | -
1024 | - | { | -
1025 | - | /* not common enough to inline */ | -
1026 | - | ExecEvalFuncExprFusage(state, op, econtext); | -
1027 | - |  | -
1028 | - | EEO_NEXT(); | -
1029 | - | } | -
1030 | - |  | -
1031 | - | EEO_CASE(EEOP_FUNCEXPR_STRICT_FUSAGE) | -
1032 | - | { | -
1033 | - | /* not common enough to inline */ | -
1034 | - | ExecEvalFuncExprStrictFusage(state, op, econtext); | -
1035 | - |  | -
1036 | - | EEO_NEXT(); | -
1037 | - | } | -
1038 | - |  | -
1039 | - | /* | -
1040 | - | * If any of its clauses is FALSE, an AND's result is FALSE regardless | -
1041 | - | * of the states of the rest of the clauses, so we can stop evaluating | -
1042 | - | * and return FALSE immediately. If none are FALSE and one or more is | -
1043 | - | * NULL, we return NULL; otherwise we return TRUE. This makes sense | -
1044 | - | * when you interpret NULL as "don't know": perhaps one of the "don't | -
1045 | - | * knows" would have been FALSE if we'd known its value. Only when | -
1046 | - | * all the inputs are known to be TRUE can we state confidently that | -
1047 | - | * the AND's result is TRUE. | -
1048 | - | */ | -
1049 | - | EEO_CASE(EEOP_BOOL_AND_STEP_FIRST) | -
1050 | - | { | -
1051 | - | *op->d.boolexpr.anynull = false; | -
1052 | - |  | -
1053 | - | /* | -
1054 | - | * EEOP_BOOL_AND_STEP_FIRST resets anynull, otherwise it's the | -
1055 | - | * same as EEOP_BOOL_AND_STEP - so fall through to that. | -
1056 | - | */ | -
1057 | - |  | -
1058 | - | /* FALL THROUGH */ | -
1059 | - | } | -
1060 | - |  | -
1061 | - | EEO_CASE(EEOP_BOOL_AND_STEP) | -
1062 | - | { | -
1063 | - | if (*op->resnull) | -
1064 | - | { | -
1065 | - | *op->d.boolexpr.anynull = true; | -
1066 | - | } | -
1067 | - | else if (!DatumGetBool(*op->resvalue)) | -
1068 | - | { | -
1069 | - | /* result is already set to FALSE, need not change it */ | -
1070 | - | /* bail out early */ | -
1071 | - | EEO_JUMP(op->d.boolexpr.jumpdone); | -
1072 | - | } | -
1073 | - |  | -
1074 | - | EEO_NEXT(); | -
1075 | - | } | -
1076 | - |  | -
1077 | - | EEO_CASE(EEOP_BOOL_AND_STEP_LAST) | -
1078 | - | { | -
1079 | - | if (*op->resnull) | -
1080 | - | { | -
1081 | - | /* result is already set to NULL, need not change it */ | -
1082 | - | } | -
1083 | - | else if (!DatumGetBool(*op->resvalue)) | -
1084 | - | { | -
1085 | - | /* result is already set to FALSE, need not change it */ | -
1086 | - |  | -
1087 | - | /* | -
1088 | - | * No point jumping early to jumpdone - would be same target | -
1089 | - | * (as this is the last argument to the AND expression), | -
1090 | - | * except more expensive. | -
1091 | - | */ | -
1092 | - | } | -
1093 | - | else if (*op->d.boolexpr.anynull) | -
1094 | - | { | -
1095 | - | *op->resvalue = (Datum) 0; | -
1096 | - | *op->resnull = true; | -
1097 | - | } | -
1098 | - | else | -
1099 | - | { | -
1100 | - | /* result is already set to TRUE, need not change it */ | -
1101 | - | } | -
1102 | - |  | -
1103 | - | EEO_NEXT(); | -
1104 | - | } | -
1105 | - |  | -
1106 | - | /* | -
1107 | - | * If any of its clauses is TRUE, an OR's result is TRUE regardless of | -
1108 | - | * the states of the rest of the clauses, so we can stop evaluating | -
1109 | - | * and return TRUE immediately. If none are TRUE and one or more is | -
1110 | - | * NULL, we return NULL; otherwise we return FALSE. This makes sense | -
1111 | - | * when you interpret NULL as "don't know": perhaps one of the "don't | -
1112 | - | * knows" would have been TRUE if we'd known its value. Only when all | -
1113 | - | * the inputs are known to be FALSE can we state confidently that the | -
1114 | - | * OR's result is FALSE. | -
1115 | - | */ | -
1116 | - | EEO_CASE(EEOP_BOOL_OR_STEP_FIRST) | -
1117 | - | { | -
1118 | - | *op->d.boolexpr.anynull = false; | -
1119 | - |  | -
1120 | - | /* | -
1121 | - | * EEOP_BOOL_OR_STEP_FIRST resets anynull, otherwise it's the same | -
1122 | - | * as EEOP_BOOL_OR_STEP - so fall through to that. | -
1123 | - | */ | -
1124 | - |  | -
1125 | - | /* FALL THROUGH */ | -
1126 | - | } | -
1127 | - |  | -
1128 | - | EEO_CASE(EEOP_BOOL_OR_STEP) | -
1129 | - | { | -
1130 | - | if (*op->resnull) | -
1131 | - | { | -
1132 | - | *op->d.boolexpr.anynull = true; | -
1133 | - | } | -
1134 | - | else if (DatumGetBool(*op->resvalue)) | -
1135 | - | { | -
1136 | - | /* result is already set to TRUE, need not change it */ | -
1137 | - | /* bail out early */ | -
1138 | - | EEO_JUMP(op->d.boolexpr.jumpdone); | -
1139 | - | } | -
1140 | - |  | -
1141 | - | EEO_NEXT(); | -
1142 | - | } | -
1143 | - |  | -
1144 | - | EEO_CASE(EEOP_BOOL_OR_STEP_LAST) | -
1145 | - | { | -
1146 | - | if (*op->resnull) | -
1147 | - | { | -
1148 | - | /* result is already set to NULL, need not change it */ | -
1149 | - | } | -
1150 | - | else if (DatumGetBool(*op->resvalue)) | -
1151 | - | { | -
1152 | - | /* result is already set to TRUE, need not change it */ | -
1153 | - |  | -
1154 | - | /* | -
1155 | - | * No point jumping to jumpdone - would be same target (as | -
1156 | - | * this is the last argument to the AND expression), except | -
1157 | - | * more expensive. | -
1158 | - | */ | -
1159 | - | } | -
1160 | - | else if (*op->d.boolexpr.anynull) | -
1161 | - | { | -
1162 | - | *op->resvalue = (Datum) 0; | -
1163 | - | *op->resnull = true; | -
1164 | - | } | -
1165 | - | else | -
1166 | - | { | -
1167 | - | /* result is already set to FALSE, need not change it */ | -
1168 | - | } | -
1169 | - |  | -
1170 | - | EEO_NEXT(); | -
1171 | - | } | -
1172 | - |  | -
1173 | - | EEO_CASE(EEOP_BOOL_NOT_STEP) | -
1174 | - | { | -
1175 | - | /* | -
1176 | - | * Evaluation of 'not' is simple... if expr is false, then return | -
1177 | - | * 'true' and vice versa. It's safe to do this even on a | -
1178 | - | * nominally null value, so we ignore resnull; that means that | -
1179 | - | * NULL in produces NULL out, which is what we want. | -
1180 | - | */ | -
1181 | - | *op->resvalue = BoolGetDatum(!DatumGetBool(*op->resvalue)); | -
1182 | - |  | -
1183 | - | EEO_NEXT(); | -
1184 | - | } | -
1185 | - |  | -
1186 | - | EEO_CASE(EEOP_QUAL) | -
1187 | - | { | -
1188 | - | /* simplified version of BOOL_AND_STEP for use by ExecQual() */ | -
1189 | - |  | -
1190 | - | /* If argument (also result) is false or null ... */ | -
1191 | - | if (*op->resnull || | -
1192 | - | !DatumGetBool(*op->resvalue)) | -
1193 | - | { | -
1194 | - | /* ... bail out early, returning FALSE */ | -
1195 | - | *op->resnull = false; | -
1196 | - | *op->resvalue = BoolGetDatum(false); | -
1197 | - | EEO_JUMP(op->d.qualexpr.jumpdone); | -
1198 | - | } | -
1199 | - |  | -
1200 | - | /* | -
1201 | - | * Otherwise, leave the TRUE value in place, in case this is the | -
1202 | - | * last qual. Then, TRUE is the correct answer. | -
1203 | - | */ | -
1204 | - |  | -
1205 | - | EEO_NEXT(); | -
1206 | - | } | -
1207 | - |  | -
1208 | - | EEO_CASE(EEOP_JUMP) | -
1209 | - | { | -
1210 | - | /* Unconditionally jump to target step */ | -
1211 | - | EEO_JUMP(op->d.jump.jumpdone); | -
1212 | - | } | -
1213 | - |  | -
1214 | - | EEO_CASE(EEOP_JUMP_IF_NULL) | -
1215 | - | { | -
1216 | - | /* Transfer control if current result is null */ | -
1217 | - | if (*op->resnull) | -
1218 | - | EEO_JUMP(op->d.jump.jumpdone); | -
1219 | - |  | -
1220 | - | EEO_NEXT(); | -
1221 | - | } | -
1222 | - |  | -
1223 | - | EEO_CASE(EEOP_JUMP_IF_NOT_NULL) | -
1224 | - | { | -
1225 | - | /* Transfer control if current result is non-null */ | -
1226 | - | if (!*op->resnull) | -
1227 | - | EEO_JUMP(op->d.jump.jumpdone); | -
1228 | - |  | -
1229 | - | EEO_NEXT(); | -
1230 | - | } | -
1231 | - |  | -
1232 | - | EEO_CASE(EEOP_JUMP_IF_NOT_TRUE) | -
1233 | - | { | -
1234 | - | /* Transfer control if current result is null or false */ | -
1235 | - | if (*op->resnull || !DatumGetBool(*op->resvalue)) | -
1236 | - | EEO_JUMP(op->d.jump.jumpdone); | -
1237 | - |  | -
1238 | - | EEO_NEXT(); | -
1239 | - | } | -
1240 | - |  | -
1241 | - | EEO_CASE(EEOP_NULLTEST_ISNULL) | -
1242 | - | { | -
1243 | - | *op->resvalue = BoolGetDatum(*op->resnull); | -
1244 | - | *op->resnull = false; | -
1245 | - |  | -
1246 | - | EEO_NEXT(); | -
1247 | - | } | -
1248 | - |  | -
1249 | - | EEO_CASE(EEOP_NULLTEST_ISNOTNULL) | -
1250 | - | { | -
1251 | - | *op->resvalue = BoolGetDatum(!*op->resnull); | -
1252 | - | *op->resnull = false; | -
1253 | - |  | -
1254 | - | EEO_NEXT(); | -
1255 | - | } | -
1256 | - |  | -
1257 | - | EEO_CASE(EEOP_NULLTEST_ROWISNULL) | -
1258 | - | { | -
1259 | - | /* out of line implementation: too large */ | -
1260 | - | ExecEvalRowNull(state, op, econtext); | -
1261 | - |  | -
1262 | - | EEO_NEXT(); | -
1263 | - | } | -
1264 | - |  | -
1265 | - | EEO_CASE(EEOP_NULLTEST_ROWISNOTNULL) | -
1266 | - | { | -
1267 | - | /* out of line implementation: too large */ | -
1268 | - | ExecEvalRowNotNull(state, op, econtext); | -
1269 | - |  | -
1270 | - | EEO_NEXT(); | -
1271 | - | } | -
1272 | - |  | -
1273 | - | /* BooleanTest implementations for all booltesttypes */ | -
1274 | - |  | -
1275 | - | EEO_CASE(EEOP_BOOLTEST_IS_TRUE) | -
1276 | - | { | -
1277 | - | if (*op->resnull) | -
1278 | - | { | -
1279 | - | *op->resvalue = BoolGetDatum(false); | -
1280 | - | *op->resnull = false; | -
1281 | - | } | -
1282 | - | /* else, input value is the correct output as well */ | -
1283 | - |  | -
1284 | - | EEO_NEXT(); | -
1285 | - | } | -
1286 | - |  | -
1287 | - | EEO_CASE(EEOP_BOOLTEST_IS_NOT_TRUE) | -
1288 | - | { | -
1289 | - | if (*op->resnull) | -
1290 | - | { | -
1291 | - | *op->resvalue = BoolGetDatum(true); | -
1292 | - | *op->resnull = false; | -
1293 | - | } | -
1294 | - | else | -
1295 | - | *op->resvalue = BoolGetDatum(!DatumGetBool(*op->resvalue)); | -
1296 | - |  | -
1297 | - | EEO_NEXT(); | -
1298 | - | } | -
1299 | - |  | -
1300 | - | EEO_CASE(EEOP_BOOLTEST_IS_FALSE) | -
1301 | - | { | -
1302 | - | if (*op->resnull) | -
1303 | - | { | -
1304 | - | *op->resvalue = BoolGetDatum(false); | -
1305 | - | *op->resnull = false; | -
1306 | - | } | -
1307 | - | else | -
1308 | - | *op->resvalue = BoolGetDatum(!DatumGetBool(*op->resvalue)); | -
1309 | - |  | -
1310 | - | EEO_NEXT(); | -
1311 | - | } | -
1312 | - |  | -
1313 | - | EEO_CASE(EEOP_BOOLTEST_IS_NOT_FALSE) | -
1314 | - | { | -
1315 | - | if (*op->resnull) | -
1316 | - | { | -
1317 | - | *op->resvalue = BoolGetDatum(true); | -
1318 | - | *op->resnull = false; | -
1319 | - | } | -
1320 | - | /* else, input value is the correct output as well */ | -
1321 | - |  | -
1322 | - | EEO_NEXT(); | -
1323 | - | } | -
1324 | - |  | -
1325 | - | EEO_CASE(EEOP_PARAM_EXEC) | -
1326 | - | { | -
1327 | - | /* out of line implementation: too large */ | -
1328 | - | ExecEvalParamExec(state, op, econtext); | -
1329 | - |  | -
1330 | - | EEO_NEXT(); | -
1331 | - | } | -
1332 | - |  | -
1333 | - | EEO_CASE(EEOP_PARAM_EXTERN) | -
1334 | - | { | -
1335 | - | /* out of line implementation: too large */ | -
1336 | - | ExecEvalParamExtern(state, op, econtext); | -
1337 | - | EEO_NEXT(); | -
1338 | - | } | -
1339 | - |  | -
1340 | - | EEO_CASE(EEOP_PARAM_CALLBACK) | -
1341 | - | { | -
1342 | - | /* allow an extension module to supply a PARAM_EXTERN value */ | -
1343 | - | op->d.cparam.paramfunc(state, op, econtext); | -
1344 | - | EEO_NEXT(); | -
1345 | - | } | -
1346 | - |  | -
1347 | - | EEO_CASE(EEOP_PARAM_SET) | -
1348 | - | { | -
1349 | - | /* out of line, unlikely to matter performance-wise */ | -
1350 | - | ExecEvalParamSet(state, op, econtext); | -
1351 | - | EEO_NEXT(); | -
1352 | - | } | -
1353 | - |  | -
1354 | - | EEO_CASE(EEOP_CASE_TESTVAL) | -
1355 | - | { | -
1356 | - | *op->resvalue = *op->d.casetest.value; | -
1357 | - | *op->resnull = *op->d.casetest.isnull; | -
1358 | - |  | -
1359 | - | EEO_NEXT(); | -
1360 | - | } | -
1361 | - |  | -
1362 | - | EEO_CASE(EEOP_CASE_TESTVAL_EXT) | -
1363 | - | { | -
1364 | - | *op->resvalue = econtext->caseValue_datum; | -
1365 | - | *op->resnull = econtext->caseValue_isNull; | -
1366 | - |  | -
1367 | - | EEO_NEXT(); | -
1368 | - | } | -
1369 | - |  | -
1370 | - | EEO_CASE(EEOP_MAKE_READONLY) | -
1371 | - | { | -
1372 | - | /* | -
1373 | - | * Force a varlena value that might be read multiple times to R/O | -
1374 | - | */ | -
1375 | - | if (!*op->d.make_readonly.isnull) | -
1376 | - | *op->resvalue = | -
1377 | - | MakeExpandedObjectReadOnlyInternal(*op->d.make_readonly.value); | -
1378 | - | *op->resnull = *op->d.make_readonly.isnull; | -
1379 | - |  | -
1380 | - | EEO_NEXT(); | -
1381 | - | } | -
1382 | - |  | -
1383 | - | EEO_CASE(EEOP_IOCOERCE) | -
1384 | - | { | -
1385 | - | /* | -
1386 | - | * Evaluate a CoerceViaIO node. This can be quite a hot path, so | -
1387 | - | * inline as much work as possible. The source value is in our | -
1388 | - | * result variable. | -
1389 | - | * | -
1390 | - | * Also look at ExecEvalCoerceViaIOSafe() if you change anything | -
1391 | - | * here. | -
1392 | - | */ | -
1393 | - | char *str; | -
1394 | - |  | -
1395 | - | /* call output function (similar to OutputFunctionCall) */ | -
1396 | - | if (*op->resnull) | -
1397 | - | { | -
1398 | - | /* output functions are not called on nulls */ | -
1399 | - | str = NULL; | -
1400 | - | } | -
1401 | - | else | -
1402 | - | { | -
1403 | - | FunctionCallInfo fcinfo_out; | -
1404 | - |  | -
1405 | - | fcinfo_out = op->d.iocoerce.fcinfo_data_out; | -
1406 | - | fcinfo_out->args[0].value = *op->resvalue; | -
1407 | - | fcinfo_out->args[0].isnull = false; | -
1408 | - |  | -
1409 | - | fcinfo_out->isnull = false; | -
1410 | - | str = DatumGetCString(FunctionCallInvoke(fcinfo_out)); | -
1411 | - |  | -
1412 | - | /* OutputFunctionCall assumes result isn't null */ | -
1413 | - | Assert(!fcinfo_out->isnull); | -
1414 | - | } | -
1415 | - |  | -
1416 | - | /* call input function (similar to InputFunctionCall) */ | -
1417 | - | if (!op->d.iocoerce.finfo_in->fn_strict || str != NULL) | -
1418 | - | { | -
1419 | - | FunctionCallInfo fcinfo_in; | -
1420 | - | Datum d; | -
1421 | - |  | -
1422 | - | fcinfo_in = op->d.iocoerce.fcinfo_data_in; | -
1423 | - | fcinfo_in->args[0].value = PointerGetDatum(str); | -
1424 | - | fcinfo_in->args[0].isnull = *op->resnull; | -
1425 | - | /* second and third arguments are already set up */ | -
1426 | - |  | -
1427 | - | fcinfo_in->isnull = false; | -
1428 | - | d = FunctionCallInvoke(fcinfo_in); | -
1429 | - | *op->resvalue = d; | -
1430 | - |  | -
1431 | - | /* Should get null result if and only if str is NULL */ | -
1432 | - | if (str == NULL) | -
1433 | - | { | -
1434 | - | Assert(*op->resnull); | -
1435 | - | Assert(fcinfo_in->isnull); | -
1436 | - | } | -
1437 | - | else | -
1438 | - | { | -
1439 | - | Assert(!*op->resnull); | -
1440 | - | Assert(!fcinfo_in->isnull); | -
1441 | - | } | -
1442 | - | } | -
1443 | - |  | -
1444 | - | EEO_NEXT(); | -
1445 | - | } | -
1446 | - |  | -
1447 | - | EEO_CASE(EEOP_IOCOERCE_SAFE) | -
1448 | - | { | -
1449 | - | ExecEvalCoerceViaIOSafe(state, op); | -
1450 | - | EEO_NEXT(); | -
1451 | - | } | -
1452 | - |  | -
1453 | - | EEO_CASE(EEOP_DISTINCT) | -
1454 | - | { | -
1455 | - | /* | -
1456 | - | * IS DISTINCT FROM must evaluate arguments (already done into | -
1457 | - | * fcinfo->args) to determine whether they are NULL; if either is | -
1458 | - | * NULL then the result is determined. If neither is NULL, then | -
1459 | - | * proceed to evaluate the comparison function, which is just the | -
1460 | - | * type's standard equality operator. We need not care whether | -
1461 | - | * that function is strict. Because the handling of nulls is | -
1462 | - | * different, we can't just reuse EEOP_FUNCEXPR. | -
1463 | - | */ | -
1464 | - | FunctionCallInfo fcinfo = op->d.func.fcinfo_data; | -
1465 | - |  | -
1466 | - | /* check function arguments for NULLness */ | -
1467 | - | if (fcinfo->args[0].isnull && fcinfo->args[1].isnull) | -
1468 | - | { | -
1469 | - | /* Both NULL? Then is not distinct... */ | -
1470 | - | *op->resvalue = BoolGetDatum(false); | -
1471 | - | *op->resnull = false; | -
1472 | - | } | -
1473 | - | else if (fcinfo->args[0].isnull || fcinfo->args[1].isnull) | -
1474 | - | { | -
1475 | - | /* Only one is NULL? Then is distinct... */ | -
1476 | - | *op->resvalue = BoolGetDatum(true); | -
1477 | - | *op->resnull = false; | -
1478 | - | } | -
1479 | - | else | -
1480 | - | { | -
1481 | - | /* Neither null, so apply the equality function */ | -
1482 | - | Datum eqresult; | -
1483 | - |  | -
1484 | - | fcinfo->isnull = false; | -
1485 | - | eqresult = op->d.func.fn_addr(fcinfo); | -
1486 | - | /* Must invert result of "="; safe to do even if null */ | -
1487 | - | *op->resvalue = BoolGetDatum(!DatumGetBool(eqresult)); | -
1488 | - | *op->resnull = fcinfo->isnull; | -
1489 | - | } | -
1490 | - |  | -
1491 | - | EEO_NEXT(); | -
1492 | - | } | -
1493 | - |  | -
1494 | - | /* see EEOP_DISTINCT for comments, this is just inverted */ | -
1495 | - | EEO_CASE(EEOP_NOT_DISTINCT) | -
1496 | - | { | -
1497 | - | FunctionCallInfo fcinfo = op->d.func.fcinfo_data; | -
1498 | - |  | -
1499 | - | if (fcinfo->args[0].isnull && fcinfo->args[1].isnull) | -
1500 | - | { | -
1501 | - | *op->resvalue = BoolGetDatum(true); | -
1502 | - | *op->resnull = false; | -
1503 | - | } | -
1504 | - | else if (fcinfo->args[0].isnull || fcinfo->args[1].isnull) | -
1505 | - | { | -
1506 | - | *op->resvalue = BoolGetDatum(false); | -
1507 | - | *op->resnull = false; | -
1508 | - | } | -
1509 | - | else | -
1510 | - | { | -
1511 | - | Datum eqresult; | -
1512 | - |  | -
1513 | - | fcinfo->isnull = false; | -
1514 | - | eqresult = op->d.func.fn_addr(fcinfo); | -
1515 | - | *op->resvalue = eqresult; | -
1516 | - | *op->resnull = fcinfo->isnull; | -
1517 | - | } | -
1518 | - |  | -
1519 | - | EEO_NEXT(); | -
1520 | - | } | -
1521 | - |  | -
1522 | - | EEO_CASE(EEOP_NULLIF) | -
1523 | - | { | -
1524 | - | /* | -
1525 | - | * The arguments are already evaluated into fcinfo->args. | -
1526 | - | */ | -
1527 | - | FunctionCallInfo fcinfo = op->d.func.fcinfo_data; | -
1528 | - | Datum save_arg0 = fcinfo->args[0].value; | -
1529 | - |  | -
1530 | - | /* if either argument is NULL they can't be equal */ | -
1531 | - | if (!fcinfo->args[0].isnull && !fcinfo->args[1].isnull) | -
1532 | - | { | -
1533 | - | Datum result; | -
1534 | - |  | -
1535 | - | /* | -
1536 | - | * If first argument is of varlena type, it might be an | -
1537 | - | * expanded datum. We need to ensure that the value passed to | -
1538 | - | * the comparison function is a read-only pointer. However, | -
1539 | - | * if we end by returning the first argument, that will be the | -
1540 | - | * original read-write pointer if it was read-write. | -
1541 | - | */ | -
1542 | - | if (op->d.func.make_ro) | -
1543 | - | fcinfo->args[0].value = | -
1544 | - | MakeExpandedObjectReadOnlyInternal(save_arg0); | -
1545 | - |  | -
1546 | - | fcinfo->isnull = false; | -
1547 | - | result = op->d.func.fn_addr(fcinfo); | -
1548 | - |  | -
1549 | - | /* if the arguments are equal return null */ | -
1550 | - | if (!fcinfo->isnull && DatumGetBool(result)) | -
1551 | - | { | -
1552 | - | *op->resvalue = (Datum) 0; | -
1553 | - | *op->resnull = true; | -
1554 | - |  | -
1555 | - | EEO_NEXT(); | -
1556 | - | } | -
1557 | - | } | -
1558 | - |  | -
1559 | - | /* Arguments aren't equal, so return the first one */ | -
1560 | - | *op->resvalue = save_arg0; | -
1561 | - | *op->resnull = fcinfo->args[0].isnull; | -
1562 | - |  | -
1563 | - | EEO_NEXT(); | -
1564 | - | } | -
1565 | - |  | -
1566 | - | EEO_CASE(EEOP_SQLVALUEFUNCTION) | -
1567 | - | { | -
1568 | - | /* | -
1569 | - | * Doesn't seem worthwhile to have an inline implementation | -
1570 | - | * efficiency-wise. | -
1571 | - | */ | -
1572 | - | ExecEvalSQLValueFunction(state, op); | -
1573 | - |  | -
1574 | - | EEO_NEXT(); | -
1575 | - | } | -
1576 | - |  | -
1577 | - | EEO_CASE(EEOP_CURRENTOFEXPR) | -
1578 | - | { | -
1579 | - | /* error invocation uses space, and shouldn't ever occur */ | -
1580 | - | ExecEvalCurrentOfExpr(state, op); | -
1581 | - |  | -
1582 | - | EEO_NEXT(); | -
1583 | - | } | -
1584 | - |  | -
1585 | - | EEO_CASE(EEOP_NEXTVALUEEXPR) | -
1586 | - | { | -
1587 | - | /* | -
1588 | - | * Doesn't seem worthwhile to have an inline implementation | -
1589 | - | * efficiency-wise. | -
1590 | - | */ | -
1591 | - | ExecEvalNextValueExpr(state, op); | -
1592 | - |  | -
1593 | - | EEO_NEXT(); | -
1594 | - | } | -
1595 | - |  | -
1596 | - | EEO_CASE(EEOP_RETURNINGEXPR) | -
1597 | - | { | -
1598 | - | /* | -
1599 | - | * The next op actually evaluates the expression. If the OLD/NEW | -
1600 | - | * row doesn't exist, skip that and return NULL. | -
1601 | - | */ | -
1602 | - | if (state->flags & op->d.returningexpr.nullflag) | -
1603 | - | { | -
1604 | - | *op->resvalue = (Datum) 0; | -
1605 | - | *op->resnull = true; | -
1606 | - |  | -
1607 | - | EEO_JUMP(op->d.returningexpr.jumpdone); | -
1608 | - | } | -
1609 | - |  | -
1610 | - | EEO_NEXT(); | -
1611 | - | } | -
1612 | - |  | -
1613 | - | EEO_CASE(EEOP_ARRAYEXPR) | -
1614 | - | { | -
1615 | - | /* too complex for an inline implementation */ | -
1616 | - | ExecEvalArrayExpr(state, op); | -
1617 | - |  | -
1618 | - | EEO_NEXT(); | -
1619 | - | } | -
1620 | - |  | -
1621 | - | EEO_CASE(EEOP_ARRAYCOERCE) | -
1622 | - | { | -
1623 | - | /* too complex for an inline implementation */ | -
1624 | - | ExecEvalArrayCoerce(state, op, econtext); | -
1625 | - |  | -
1626 | - | EEO_NEXT(); | -
1627 | - | } | -
1628 | - |  | -
1629 | - | EEO_CASE(EEOP_ROW) | -
1630 | - | { | -
1631 | - | /* too complex for an inline implementation */ | -
1632 | - | ExecEvalRow(state, op); | -
1633 | - |  | -
1634 | - | EEO_NEXT(); | -
1635 | - | } | -
1636 | - |  | -
1637 | - | EEO_CASE(EEOP_ROWCOMPARE_STEP) | -
1638 | - | { | -
1639 | - | FunctionCallInfo fcinfo = op->d.rowcompare_step.fcinfo_data; | -
1640 | - | Datum d; | -
1641 | - |  | -
1642 | - | /* force NULL result if strict fn and NULL input */ | -
1643 | - | if (op->d.rowcompare_step.finfo->fn_strict && | -
1644 | - | (fcinfo->args[0].isnull || fcinfo->args[1].isnull)) | -
1645 | - | { | -
1646 | - | *op->resnull = true; | -
1647 | - | EEO_JUMP(op->d.rowcompare_step.jumpnull); | -
1648 | - | } | -
1649 | - |  | -
1650 | - | /* Apply comparison function */ | -
1651 | - | fcinfo->isnull = false; | -
1652 | - | d = op->d.rowcompare_step.fn_addr(fcinfo); | -
1653 | - | *op->resvalue = d; | -
1654 | - |  | -
1655 | - | /* force NULL result if NULL function result */ | -
1656 | - | if (fcinfo->isnull) | -
1657 | - | { | -
1658 | - | *op->resnull = true; | -
1659 | - | EEO_JUMP(op->d.rowcompare_step.jumpnull); | -
1660 | - | } | -
1661 | - | *op->resnull = false; | -
1662 | - |  | -
1663 | - | /* If unequal, no need to compare remaining columns */ | -
1664 | - | if (DatumGetInt32(*op->resvalue) != 0) | -
1665 | - | { | -
1666 | - | EEO_JUMP(op->d.rowcompare_step.jumpdone); | -
1667 | - | } | -
1668 | - |  | -
1669 | - | EEO_NEXT(); | -
1670 | - | } | -
1671 | - |  | -
1672 | - | EEO_CASE(EEOP_ROWCOMPARE_FINAL) | -
1673 | - | { | -
1674 | - | int32 cmpresult = DatumGetInt32(*op->resvalue); | -
1675 | - | CompareType cmptype = op->d.rowcompare_final.cmptype; | -
1676 | - |  | -
1677 | - | *op->resnull = false; | -
1678 | - | switch (cmptype) | -
1679 | - | { | -
1680 | - | /* EQ and NE cases aren't allowed here */ | -
1681 | - | case COMPARE_LT: | -
1682 | - | *op->resvalue = BoolGetDatum(cmpresult < 0); | -
1683 | - | break; | -
1684 | - | case COMPARE_LE: | -
1685 | - | *op->resvalue = BoolGetDatum(cmpresult <= 0); | -
1686 | - | break; | -
1687 | - | case COMPARE_GE: | -
1688 | - | *op->resvalue = BoolGetDatum(cmpresult >= 0); | -
1689 | - | break; | -
1690 | - | case COMPARE_GT: | -
1691 | - | *op->resvalue = BoolGetDatum(cmpresult > 0); | -
1692 | - | break; | -
1693 | - | default: | -
1694 | - | Assert(false); | -
1695 | - | break; | -
1696 | - | } | -
1697 | - |  | -
1698 | - | EEO_NEXT(); | -
1699 | - | } | -
1700 | - |  | -
1701 | - | EEO_CASE(EEOP_MINMAX) | -
1702 | - | { | -
1703 | - | /* too complex for an inline implementation */ | -
1704 | - | ExecEvalMinMax(state, op); | -
1705 | - |  | -
1706 | - | EEO_NEXT(); | -
1707 | - | } | -
1708 | - |  | -
1709 | - | EEO_CASE(EEOP_FIELDSELECT) | -
1710 | - | { | -
1711 | - | /* too complex for an inline implementation */ | -
1712 | - | ExecEvalFieldSelect(state, op, econtext); | -
1713 | - |  | -
1714 | - | EEO_NEXT(); | -
1715 | - | } | -
1716 | - |  | -
1717 | - | EEO_CASE(EEOP_FIELDSTORE_DEFORM) | -
1718 | - | { | -
1719 | - | /* too complex for an inline implementation */ | -
1720 | - | ExecEvalFieldStoreDeForm(state, op, econtext); | -
1721 | - |  | -
1722 | - | EEO_NEXT(); | -
1723 | - | } | -
1724 | - |  | -
1725 | - | EEO_CASE(EEOP_FIELDSTORE_FORM) | -
1726 | - | { | -
1727 | - | /* too complex for an inline implementation */ | -
1728 | - | ExecEvalFieldStoreForm(state, op, econtext); | -
1729 | - |  | -
1730 | - | EEO_NEXT(); | -
1731 | - | } | -
1732 | - |  | -
1733 | - | EEO_CASE(EEOP_SBSREF_SUBSCRIPTS) | -
1734 | - | { | -
1735 | - | /* Precheck SubscriptingRef subscript(s) */ | -
1736 | - | if (op->d.sbsref_subscript.subscriptfunc(state, op, econtext)) | -
1737 | - | { | -
1738 | - | EEO_NEXT(); | -
1739 | - | } | -
1740 | - | else | -
1741 | - | { | -
1742 | - | /* Subscript is null, short-circuit SubscriptingRef to NULL */ | -
1743 | - | EEO_JUMP(op->d.sbsref_subscript.jumpdone); | -
1744 | - | } | -
1745 | - | } | -
1746 | - |  | -
1747 | - | EEO_CASE(EEOP_SBSREF_OLD) | -
1748 | - | EEO_CASE(EEOP_SBSREF_ASSIGN) | -
1749 | - | EEO_CASE(EEOP_SBSREF_FETCH) | -
1750 | - | { | -
1751 | - | /* Perform a SubscriptingRef fetch or assignment */ | -
1752 | - | op->d.sbsref.subscriptfunc(state, op, econtext); | -
1753 | - |  | -
1754 | - | EEO_NEXT(); | -
1755 | - | } | -
1756 | - |  | -
1757 | - | EEO_CASE(EEOP_CONVERT_ROWTYPE) | -
1758 | - | { | -
1759 | - | /* too complex for an inline implementation */ | -
1760 | - | ExecEvalConvertRowtype(state, op, econtext); | -
1761 | - |  | -
1762 | - | EEO_NEXT(); | -
1763 | - | } | -
1764 | - |  | -
1765 | - | EEO_CASE(EEOP_SCALARARRAYOP) | -
1766 | - | { | -
1767 | - | /* too complex for an inline implementation */ | -
1768 | - | ExecEvalScalarArrayOp(state, op); | -
1769 | - |  | -
1770 | - | EEO_NEXT(); | -
1771 | - | } | -
1772 | - |  | -
1773 | - | EEO_CASE(EEOP_HASHED_SCALARARRAYOP) | -
1774 | - | { | -
1775 | - | /* too complex for an inline implementation */ | -
1776 | - | ExecEvalHashedScalarArrayOp(state, op, econtext); | -
1777 | - |  | -
1778 | - | EEO_NEXT(); | -
1779 | - | } | -
1780 | - |  | -
1781 | - | EEO_CASE(EEOP_DOMAIN_TESTVAL) | -
1782 | - | { | -
1783 | - | *op->resvalue = *op->d.casetest.value; | -
1784 | - | *op->resnull = *op->d.casetest.isnull; | -
1785 | - |  | -
1786 | - | EEO_NEXT(); | -
1787 | - | } | -
1788 | - |  | -
1789 | - | EEO_CASE(EEOP_DOMAIN_TESTVAL_EXT) | -
1790 | - | { | -
1791 | - | *op->resvalue = econtext->domainValue_datum; | -
1792 | - | *op->resnull = econtext->domainValue_isNull; | -
1793 | - |  | -
1794 | - | EEO_NEXT(); | -
1795 | - | } | -
1796 | - |  | -
1797 | - | EEO_CASE(EEOP_DOMAIN_NOTNULL) | -
1798 | - | { | -
1799 | - | /* too complex for an inline implementation */ | -
1800 | - | ExecEvalConstraintNotNull(state, op); | -
1801 | - |  | -
1802 | - | EEO_NEXT(); | -
1803 | - | } | -
1804 | - |  | -
1805 | - | EEO_CASE(EEOP_DOMAIN_CHECK) | -
1806 | - | { | -
1807 | - | /* too complex for an inline implementation */ | -
1808 | - | ExecEvalConstraintCheck(state, op); | -
1809 | - |  | -
1810 | - | EEO_NEXT(); | -
1811 | - | } | -
1812 | - |  | -
1813 | - | EEO_CASE(EEOP_HASHDATUM_SET_INITVAL) | -
1814 | - | { | -
1815 | - | *op->resvalue = op->d.hashdatum_initvalue.init_value; | -
1816 | - | *op->resnull = false; | -
1817 | - |  | -
1818 | - | EEO_NEXT(); | -
1819 | - | } | -
1820 | - |  | -
1821 | - | EEO_CASE(EEOP_HASHDATUM_FIRST) | -
1822 | - | { | -
1823 | - | FunctionCallInfo fcinfo = op->d.hashdatum.fcinfo_data; | -
1824 | - |  | -
1825 | - | /* | -
1826 | - | * Save the Datum on non-null inputs, otherwise store 0 so that | -
1827 | - | * subsequent NEXT32 operations combine with an initialized value. | -
1828 | - | */ | -
1829 | - | if (!fcinfo->args[0].isnull) | -
1830 | - | *op->resvalue = op->d.hashdatum.fn_addr(fcinfo); | -
1831 | - | else | -
1832 | - | *op->resvalue = (Datum) 0; | -
1833 | - |  | -
1834 | - | *op->resnull = false; | -
1835 | - |  | -
1836 | - | EEO_NEXT(); | -
1837 | - | } | -
1838 | - |  | -
1839 | - | EEO_CASE(EEOP_HASHDATUM_FIRST_STRICT) | -
1840 | - | { | -
1841 | - | FunctionCallInfo fcinfo = op->d.hashdatum.fcinfo_data; | -
1842 | - |  | -
1843 | - | if (fcinfo->args[0].isnull) | -
1844 | - | { | -
1845 | - | /* | -
1846 | - | * With strict we have the expression return NULL instead of | -
1847 | - | * ignoring NULL input values. We've nothing more to do after | -
1848 | - | * finding a NULL. | -
1849 | - | */ | -
1850 | - | *op->resnull = true; | -
1851 | - | *op->resvalue = (Datum) 0; | -
1852 | - | EEO_JUMP(op->d.hashdatum.jumpdone); | -
1853 | - | } | -
1854 | - |  | -
1855 | - | /* execute the hash function and save the resulting value */ | -
1856 | - | *op->resvalue = op->d.hashdatum.fn_addr(fcinfo); | -
1857 | - | *op->resnull = false; | -
1858 | - |  | -
1859 | - | EEO_NEXT(); | -
1860 | - | } | -
1861 | - |  | -
1862 | - | EEO_CASE(EEOP_HASHDATUM_NEXT32) | -
1863 | - | { | -
1864 | - | FunctionCallInfo fcinfo = op->d.hashdatum.fcinfo_data; | -
1865 | - | uint32 existinghash; | -
1866 | - |  | -
1867 | - | existinghash = DatumGetUInt32(op->d.hashdatum.iresult->value); | -
1868 | - | /* combine successive hash values by rotating */ | -
1869 | - | existinghash = pg_rotate_left32(existinghash, 1); | -
1870 | - |  | -
1871 | - | /* leave the hash value alone on NULL inputs */ | -
1872 | - | if (!fcinfo->args[0].isnull) | -
1873 | - | { | -
1874 | - | uint32 hashvalue; | -
1875 | - |  | -
1876 | - | /* execute hash func and combine with previous hash value */ | -
1877 | - | hashvalue = DatumGetUInt32(op->d.hashdatum.fn_addr(fcinfo)); | -
1878 | - | existinghash = existinghash ^ hashvalue; | -
1879 | - | } | -
1880 | - |  | -
1881 | - | *op->resvalue = UInt32GetDatum(existinghash); | -
1882 | - | *op->resnull = false; | -
1883 | - |  | -
1884 | - | EEO_NEXT(); | -
1885 | - | } | -
1886 | - |  | -
1887 | - | EEO_CASE(EEOP_HASHDATUM_NEXT32_STRICT) | -
1888 | - | { | -
1889 | - | FunctionCallInfo fcinfo = op->d.hashdatum.fcinfo_data; | -
1890 | - |  | -
1891 | - | if (fcinfo->args[0].isnull) | -
1892 | - | { | -
1893 | - | /* | -
1894 | - | * With strict we have the expression return NULL instead of | -
1895 | - | * ignoring NULL input values. We've nothing more to do after | -
1896 | - | * finding a NULL. | -
1897 | - | */ | -
1898 | - | *op->resnull = true; | -
1899 | - | *op->resvalue = (Datum) 0; | -
1900 | - | EEO_JUMP(op->d.hashdatum.jumpdone); | -
1901 | - | } | -
1902 | - | else | -
1903 | - | { | -
1904 | - | uint32 existinghash; | -
1905 | - | uint32 hashvalue; | -
1906 | - |  | -
1907 | - | existinghash = DatumGetUInt32(op->d.hashdatum.iresult->value); | -
1908 | - | /* combine successive hash values by rotating */ | -
1909 | - | existinghash = pg_rotate_left32(existinghash, 1); | -
1910 | - |  | -
1911 | - | /* execute hash func and combine with previous hash value */ | -
1912 | - | hashvalue = DatumGetUInt32(op->d.hashdatum.fn_addr(fcinfo)); | -
1913 | - | *op->resvalue = UInt32GetDatum(existinghash ^ hashvalue); | -
1914 | - | *op->resnull = false; | -
1915 | - | } | -
1916 | - |  | -
1917 | - | EEO_NEXT(); | -
1918 | - | } | -
1919 | - |  | -
1920 | - | EEO_CASE(EEOP_XMLEXPR) | -
1921 | - | { | -
1922 | - | /* too complex for an inline implementation */ | -
1923 | - | ExecEvalXmlExpr(state, op); | -
1924 | - |  | -
1925 | - | EEO_NEXT(); | -
1926 | - | } | -
1927 | - |  | -
1928 | - | EEO_CASE(EEOP_JSON_CONSTRUCTOR) | -
1929 | - | { | -
1930 | - | /* too complex for an inline implementation */ | -
1931 | - | ExecEvalJsonConstructor(state, op, econtext); | -
1932 | - | EEO_NEXT(); | -
1933 | - | } | -
1934 | - |  | -
1935 | - | EEO_CASE(EEOP_IS_JSON) | -
1936 | - | { | -
1937 | - | /* too complex for an inline implementation */ | -
1938 | - | ExecEvalJsonIsPredicate(state, op); | -
1939 | - |  | -
1940 | - | EEO_NEXT(); | -
1941 | - | } | -
1942 | - |  | -
1943 | - | EEO_CASE(EEOP_JSONEXPR_PATH) | -
1944 | - | { | -
1945 | - | /* too complex for an inline implementation */ | -
1946 | - | EEO_JUMP(ExecEvalJsonExprPath(state, op, econtext)); | -
1947 | - | } | -
1948 | - |  | -
1949 | - | EEO_CASE(EEOP_JSONEXPR_COERCION) | -
1950 | - | { | -
1951 | - | /* too complex for an inline implementation */ | -
1952 | - | ExecEvalJsonCoercion(state, op, econtext); | -
1953 | - |  | -
1954 | - | EEO_NEXT(); | -
1955 | - | } | -
1956 | - |  | -
1957 | - | EEO_CASE(EEOP_JSONEXPR_COERCION_FINISH) | -
1958 | - | { | -
1959 | - | /* too complex for an inline implementation */ | -
1960 | - | ExecEvalJsonCoercionFinish(state, op); | -
1961 | - |  | -
1962 | - | EEO_NEXT(); | -
1963 | - | } | -
1964 | - |  | -
1965 | - | EEO_CASE(EEOP_AGGREF) | -
1966 | - | { | -
1967 | - | /* | -
1968 | - | * Returns a Datum whose value is the precomputed aggregate value | -
1969 | - | * found in the given expression context. | -
1970 | - | */ | -
1971 | - | int aggno = op->d.aggref.aggno; | -
1972 | - |  | -
1973 | - | Assert(econtext->ecxt_aggvalues != NULL); | -
1974 | - |  | -
1975 | - | *op->resvalue = econtext->ecxt_aggvalues[aggno]; | -
1976 | - | *op->resnull = econtext->ecxt_aggnulls[aggno]; | -
1977 | - |  | -
1978 | - | EEO_NEXT(); | -
1979 | - | } | -
1980 | - |  | -
1981 | - | EEO_CASE(EEOP_GROUPING_FUNC) | -
1982 | - | { | -
1983 | - | /* too complex/uncommon for an inline implementation */ | -
1984 | - | ExecEvalGroupingFunc(state, op); | -
1985 | - |  | -
1986 | - | EEO_NEXT(); | -
1987 | - | } | -
1988 | - |  | -
1989 | - | EEO_CASE(EEOP_WINDOW_FUNC) | -
1990 | - | { | -
1991 | - | /* | -
1992 | - | * Like Aggref, just return a precomputed value from the econtext. | -
1993 | - | */ | -
1994 | - | WindowFuncExprState *wfunc = op->d.window_func.wfstate; | -
1995 | - |  | -
1996 | - | Assert(econtext->ecxt_aggvalues != NULL); | -
1997 | - |  | -
1998 | - | *op->resvalue = econtext->ecxt_aggvalues[wfunc->wfuncno]; | -
1999 | - | *op->resnull = econtext->ecxt_aggnulls[wfunc->wfuncno]; | -
2000 | - |  | -
2001 | - | EEO_NEXT(); | -
2002 | - | } | -
2003 | - |  | -
2004 | - | EEO_CASE(EEOP_MERGE_SUPPORT_FUNC) | -
2005 | - | { | -
2006 | - | /* too complex/uncommon for an inline implementation */ | -
2007 | - | ExecEvalMergeSupportFunc(state, op, econtext); | -
2008 | - |  | -
2009 | - | EEO_NEXT(); | -
2010 | - | } | -
2011 | - |  | -
2012 | - | EEO_CASE(EEOP_SUBPLAN) | -
2013 | - | { | -
2014 | - | /* too complex for an inline implementation */ | -
2015 | - | ExecEvalSubPlan(state, op, econtext); | -
2016 | - |  | -
2017 | - | EEO_NEXT(); | -
2018 | - | } | -
2019 | - |  | -
2020 | - | /* RPR navigation: swap slot to target row */ | 24cfb8dRow pattern recognition patch (executor and commands).
2021 | 176028 | EEO_CASE(EEOP_RPR_NAV_SET) | 24cfb8dRow pattern recognition patch (executor and commands).
2022 | - | { | 24cfb8dRow pattern recognition patch (executor and commands).
2023 | 176028 | ExecEvalRPRNavSet(state, op, econtext); | 24cfb8dRow pattern recognition patch (executor and commands).
2024 | 175968 | outerslot = econtext->ecxt_outertuple; | 24cfb8dRow pattern recognition patch (executor and commands).
2025 | - |  | 24cfb8dRow pattern recognition patch (executor and commands).
2026 | 175968 | EEO_NEXT(); | 24cfb8dRow pattern recognition patch (executor and commands).
2027 | - | } | 24cfb8dRow pattern recognition patch (executor and commands).
2028 | - |  | 24cfb8dRow pattern recognition patch (executor and commands).
2029 | - | /* RPR navigation: restore slot to original row */ | 24cfb8dRow pattern recognition patch (executor and commands).
2030 | 175968 | EEO_CASE(EEOP_RPR_NAV_RESTORE) | 24cfb8dRow pattern recognition patch (executor and commands).
2031 | - | { | 24cfb8dRow pattern recognition patch (executor and commands).
2032 | 175968 | ExecEvalRPRNavRestore(state, op, econtext); | 24cfb8dRow pattern recognition patch (executor and commands).
2033 | 175968 | outerslot = econtext->ecxt_outertuple; | 24cfb8dRow pattern recognition patch (executor and commands).
2034 | - |  | 24cfb8dRow pattern recognition patch (executor and commands).
2035 | 175968 | EEO_NEXT(); | 24cfb8dRow pattern recognition patch (executor and commands).
2036 | - | } | 24cfb8dRow pattern recognition patch (executor and commands).
2037 | - |  | 24cfb8dRow pattern recognition patch (executor and commands).
2038 | - | /* evaluate a strict aggregate deserialization function */ | -
2039 | - | EEO_CASE(EEOP_AGG_STRICT_DESERIALIZE) | -
2040 | - | { | -
2041 | - | /* Don't call a strict deserialization function with NULL input */ | -
2042 | - | if (op->d.agg_deserialize.fcinfo_data->args[0].isnull) | -
2043 | - | EEO_JUMP(op->d.agg_deserialize.jumpnull); | -
2044 | - |  | -
2045 | - | /* fallthrough */ | -
2046 | - | } | -
2047 | - |  | -
2048 | - | /* evaluate aggregate deserialization function (non-strict portion) */ | -
2049 | - | EEO_CASE(EEOP_AGG_DESERIALIZE) | -
2050 | - | { | -
2051 | - | FunctionCallInfo fcinfo = op->d.agg_deserialize.fcinfo_data; | -
2052 | - | AggState *aggstate = castNode(AggState, state->parent); | -
2053 | - | MemoryContext oldContext; | -
2054 | - |  | -
2055 | - | /* | -
2056 | - | * We run the deserialization functions in per-input-tuple memory | -
2057 | - | * context. | -
2058 | - | */ | -
2059 | - | oldContext = MemoryContextSwitchTo(aggstate->tmpcontext->ecxt_per_tuple_memory); | -
2060 | - | fcinfo->isnull = false; | -
2061 | - | *op->resvalue = FunctionCallInvoke(fcinfo); | -
2062 | - | *op->resnull = fcinfo->isnull; | -
2063 | - | MemoryContextSwitchTo(oldContext); | -
2064 | - |  | -
2065 | - | EEO_NEXT(); | -
2066 | - | } | -
2067 | - |  | -
2068 | - | /* | -
2069 | - | * Check that a strict aggregate transition / combination function's | -
2070 | - | * input is not NULL. | -
2071 | - | */ | -
2072 | - |  | -
2073 | - | /* when checking more than one argument */ | -
2074 | - | EEO_CASE(EEOP_AGG_STRICT_INPUT_CHECK_ARGS) | -
2075 | - | { | -
2076 | - | NullableDatum *args = op->d.agg_strict_input_check.args; | -
2077 | - | int nargs = op->d.agg_strict_input_check.nargs; | -
2078 | - |  | -
2079 | - | Assert(nargs > 1); | -
2080 | - |  | -
2081 | - | for (int argno = 0; argno < nargs; argno++) | -
2082 | - | { | -
2083 | - | if (args[argno].isnull) | -
2084 | - | EEO_JUMP(op->d.agg_strict_input_check.jumpnull); | -
2085 | - | } | -
2086 | - | EEO_NEXT(); | -
2087 | - | } | -
2088 | - |  | -
2089 | - | /* special case for just one argument */ | -
2090 | - | EEO_CASE(EEOP_AGG_STRICT_INPUT_CHECK_ARGS_1) | -
2091 | - | { | -
2092 | - | NullableDatum *args = op->d.agg_strict_input_check.args; | -
2093 | - | PG_USED_FOR_ASSERTS_ONLY int nargs = op->d.agg_strict_input_check.nargs; | -
2094 | - |  | -
2095 | - | Assert(nargs == 1); | -
2096 | - |  | -
2097 | - | if (args[0].isnull) | -
2098 | - | EEO_JUMP(op->d.agg_strict_input_check.jumpnull); | -
2099 | - | EEO_NEXT(); | -
2100 | - | } | -
2101 | - |  | -
2102 | - | EEO_CASE(EEOP_AGG_STRICT_INPUT_CHECK_NULLS) | -
2103 | - | { | -
2104 | - | bool *nulls = op->d.agg_strict_input_check.nulls; | -
2105 | - | int nargs = op->d.agg_strict_input_check.nargs; | -
2106 | - |  | -
2107 | - | for (int argno = 0; argno < nargs; argno++) | -
2108 | - | { | -
2109 | - | if (nulls[argno]) | -
2110 | - | EEO_JUMP(op->d.agg_strict_input_check.jumpnull); | -
2111 | - | } | -
2112 | - | EEO_NEXT(); | -
2113 | - | } | -
2114 | - |  | -
2115 | - | /* | -
2116 | - | * Check for a NULL pointer to the per-group states. | -
2117 | - | */ | -
2118 | - |  | -
2119 | - | EEO_CASE(EEOP_AGG_PLAIN_PERGROUP_NULLCHECK) | -
2120 | - | { | -
2121 | - | AggState *aggstate = castNode(AggState, state->parent); | -
2122 | - | AggStatePerGroup pergroup_allaggs = | -
2123 | - | aggstate->all_pergroups[op->d.agg_plain_pergroup_nullcheck.setoff]; | -
2124 | - |  | -
2125 | - | if (pergroup_allaggs == NULL) | -
2126 | - | EEO_JUMP(op->d.agg_plain_pergroup_nullcheck.jumpnull); | -
2127 | - |  | -
2128 | - | EEO_NEXT(); | -
2129 | - | } | -
2130 | - |  | -
2131 | - | /* | -
2132 | - | * Different types of aggregate transition functions are implemented | -
2133 | - | * as different types of steps, to avoid incurring unnecessary | -
2134 | - | * overhead. There's a step type for each valid combination of having | -
2135 | - | * a by value / by reference transition type, [not] needing to the | -
2136 | - | * initialize the transition value for the first row in a group from | -
2137 | - | * input, and [not] strict transition function. | -
2138 | - | * | -
2139 | - | * Could optimize further by splitting off by-reference for | -
2140 | - | * fixed-length types, but currently that doesn't seem worth it. | -
2141 | - | */ | -
2142 | - |  | -
2143 | - | EEO_CASE(EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL) | -
2144 | - | { | -
2145 | - | AggState *aggstate = castNode(AggState, state->parent); | -
2146 | - | AggStatePerTrans pertrans = op->d.agg_trans.pertrans; | -
2147 | - | AggStatePerGroup pergroup = | -
2148 | - | &aggstate->all_pergroups[op->d.agg_trans.setoff][op->d.agg_trans.transno]; | -
2149 | - |  | -
2150 | - | Assert(pertrans->transtypeByVal); | -
2151 | - |  | -
2152 | - | if (pergroup->noTransValue) | -
2153 | - | { | -
2154 | - | /* If transValue has not yet been initialized, do so now. */ | -
2155 | - | ExecAggInitGroup(aggstate, pertrans, pergroup, | -
2156 | - | op->d.agg_trans.aggcontext); | -
2157 | - | /* copied trans value from input, done this round */ | -
2158 | - | } | -
2159 | - | else if (likely(!pergroup->transValueIsNull)) | -
2160 | - | { | -
2161 | - | /* invoke transition function, unless prevented by strictness */ | -
2162 | - | ExecAggPlainTransByVal(aggstate, pertrans, pergroup, | -
2163 | - | op->d.agg_trans.aggcontext, | -
2164 | - | op->d.agg_trans.setno); | -
2165 | - | } | -
2166 | - |  | -
2167 | - | EEO_NEXT(); | -
2168 | - | } | -
2169 | - |  | -
2170 | - | /* see comments above EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL */ | -
2171 | - | EEO_CASE(EEOP_AGG_PLAIN_TRANS_STRICT_BYVAL) | -
2172 | - | { | -
2173 | - | AggState *aggstate = castNode(AggState, state->parent); | -
2174 | - | AggStatePerTrans pertrans = op->d.agg_trans.pertrans; | -
2175 | - | AggStatePerGroup pergroup = | -
2176 | - | &aggstate->all_pergroups[op->d.agg_trans.setoff][op->d.agg_trans.transno]; | -
2177 | - |  | -
2178 | - | Assert(pertrans->transtypeByVal); | -
2179 | - |  | -
2180 | - | if (likely(!pergroup->transValueIsNull)) | -
2181 | - | ExecAggPlainTransByVal(aggstate, pertrans, pergroup, | -
2182 | - | op->d.agg_trans.aggcontext, | -
2183 | - | op->d.agg_trans.setno); | -
2184 | - |  | -
2185 | - | EEO_NEXT(); | -
2186 | - | } | -
2187 | - |  | -
2188 | - | /* see comments above EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL */ | -
2189 | - | EEO_CASE(EEOP_AGG_PLAIN_TRANS_BYVAL) | -
2190 | - | { | -
2191 | - | AggState *aggstate = castNode(AggState, state->parent); | -
2192 | - | AggStatePerTrans pertrans = op->d.agg_trans.pertrans; | -
2193 | - | AggStatePerGroup pergroup = | -
2194 | - | &aggstate->all_pergroups[op->d.agg_trans.setoff][op->d.agg_trans.transno]; | -
2195 | - |  | -
2196 | - | Assert(pertrans->transtypeByVal); | -
2197 | - |  | -
2198 | - | ExecAggPlainTransByVal(aggstate, pertrans, pergroup, | -
2199 | - | op->d.agg_trans.aggcontext, | -
2200 | - | op->d.agg_trans.setno); | -
2201 | - |  | -
2202 | - | EEO_NEXT(); | -
2203 | - | } | -
2204 | - |  | -
2205 | - | /* see comments above EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL */ | -
2206 | - | EEO_CASE(EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYREF) | -
2207 | - | { | -
2208 | - | AggState *aggstate = castNode(AggState, state->parent); | -
2209 | - | AggStatePerTrans pertrans = op->d.agg_trans.pertrans; | -
2210 | - | AggStatePerGroup pergroup = | -
2211 | - | &aggstate->all_pergroups[op->d.agg_trans.setoff][op->d.agg_trans.transno]; | -
2212 | - |  | -
2213 | - | Assert(!pertrans->transtypeByVal); | -
2214 | - |  | -
2215 | - | if (pergroup->noTransValue) | -
2216 | - | ExecAggInitGroup(aggstate, pertrans, pergroup, | -
2217 | - | op->d.agg_trans.aggcontext); | -
2218 | - | else if (likely(!pergroup->transValueIsNull)) | -
2219 | - | ExecAggPlainTransByRef(aggstate, pertrans, pergroup, | -
2220 | - | op->d.agg_trans.aggcontext, | -
2221 | - | op->d.agg_trans.setno); | -
2222 | - |  | -
2223 | - | EEO_NEXT(); | -
2224 | - | } | -
2225 | - |  | -
2226 | - | /* see comments above EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL */ | -
2227 | - | EEO_CASE(EEOP_AGG_PLAIN_TRANS_STRICT_BYREF) | -
2228 | - | { | -
2229 | - | AggState *aggstate = castNode(AggState, state->parent); | -
2230 | - | AggStatePerTrans pertrans = op->d.agg_trans.pertrans; | -
2231 | - | AggStatePerGroup pergroup = | -
2232 | - | &aggstate->all_pergroups[op->d.agg_trans.setoff][op->d.agg_trans.transno]; | -
2233 | - |  | -
2234 | - | Assert(!pertrans->transtypeByVal); | -
2235 | - |  | -
2236 | - | if (likely(!pergroup->transValueIsNull)) | -
2237 | - | ExecAggPlainTransByRef(aggstate, pertrans, pergroup, | -
2238 | - | op->d.agg_trans.aggcontext, | -
2239 | - | op->d.agg_trans.setno); | -
2240 | - | EEO_NEXT(); | -
2241 | - | } | -
2242 | - |  | -
2243 | - | /* see comments above EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL */ | -
2244 | - | EEO_CASE(EEOP_AGG_PLAIN_TRANS_BYREF) | -
2245 | - | { | -
2246 | - | AggState *aggstate = castNode(AggState, state->parent); | -
2247 | - | AggStatePerTrans pertrans = op->d.agg_trans.pertrans; | -
2248 | - | AggStatePerGroup pergroup = | -
2249 | - | &aggstate->all_pergroups[op->d.agg_trans.setoff][op->d.agg_trans.transno]; | -
2250 | - |  | -
2251 | - | Assert(!pertrans->transtypeByVal); | -
2252 | - |  | -
2253 | - | ExecAggPlainTransByRef(aggstate, pertrans, pergroup, | -
2254 | - | op->d.agg_trans.aggcontext, | -
2255 | - | op->d.agg_trans.setno); | -
2256 | - |  | -
2257 | - | EEO_NEXT(); | -
2258 | - | } | -
2259 | - |  | -
2260 | - | EEO_CASE(EEOP_AGG_PRESORTED_DISTINCT_SINGLE) | -
2261 | - | { | -
2262 | - | AggStatePerTrans pertrans = op->d.agg_presorted_distinctcheck.pertrans; | -
2263 | - | AggState *aggstate = castNode(AggState, state->parent); | -
2264 | - |  | -
2265 | - | if (ExecEvalPreOrderedDistinctSingle(aggstate, pertrans)) | -
2266 | - | EEO_NEXT(); | -
2267 | - | else | -
2268 | - | EEO_JUMP(op->d.agg_presorted_distinctcheck.jumpdistinct); | -
2269 | - | } | -
2270 | - |  | -
2271 | - | EEO_CASE(EEOP_AGG_PRESORTED_DISTINCT_MULTI) | -
2272 | - | { | -
2273 | - | AggState *aggstate = castNode(AggState, state->parent); | -
2274 | - | AggStatePerTrans pertrans = op->d.agg_presorted_distinctcheck.pertrans; | -
2275 | - |  | -
2276 | - | if (ExecEvalPreOrderedDistinctMulti(aggstate, pertrans)) | -
2277 | - | EEO_NEXT(); | -
2278 | - | else | -
2279 | - | EEO_JUMP(op->d.agg_presorted_distinctcheck.jumpdistinct); | -
2280 | - | } | -
2281 | - |  | -
2282 | - | /* process single-column ordered aggregate datum */ | -
2283 | - | EEO_CASE(EEOP_AGG_ORDERED_TRANS_DATUM) | -
2284 | - | { | -
2285 | - | /* too complex for an inline implementation */ | -
2286 | - | ExecEvalAggOrderedTransDatum(state, op, econtext); | -
2287 | - |  | -
2288 | - | EEO_NEXT(); | -
2289 | - | } | -
2290 | - |  | -
2291 | - | /* process multi-column ordered aggregate tuple */ | -
2292 | - | EEO_CASE(EEOP_AGG_ORDERED_TRANS_TUPLE) | -
2293 | - | { | -
2294 | - | /* too complex for an inline implementation */ | -
2295 | - | ExecEvalAggOrderedTransTuple(state, op, econtext); | -
2296 | - |  | -
2297 | - | EEO_NEXT(); | -
2298 | - | } | -
2299 | - |  | -
2300 | - | EEO_CASE(EEOP_LAST) | -
2301 | - | { | -
2302 | - | /* unreachable */ | -
2303 | - | Assert(false); | -
2304 | - | goto out_error; | -
2305 | - | } | -
2306 | - | } | -
2307 | - |  | -
2308 | - | out_error: | -
2309 | - | pg_unreachable(); | -
2310 | - | return (Datum) 0; | -
2311 | - | } | -

rpr_nav_get_compound_offset() lines 6021-6040
Modified Lines Coverage: 9/9 lines (100.0%)

Line | Hits | Source | Commit
--- | --- | --- | ---
6021 | 9744 | rpr_nav_get_compound_offset(ExprEvalStep *op) | 24cfb8dRow pattern recognition patch (executor and commands).
6022 | - | { | 24cfb8dRow pattern recognition patch (executor and commands).
6023 | 9744 | int64 val; | 24cfb8dRow pattern recognition patch (executor and commands).
6024 | - |  | 24cfb8dRow pattern recognition patch (executor and commands).
6025 | 9744 | Assert(op->d.rpr_nav.offset_value != NULL); | 24cfb8dRow pattern recognition patch (executor and commands).
6026 | - |  | 24cfb8dRow pattern recognition patch (executor and commands).
6027 | 9744 | if (op->d.rpr_nav.offset_isnull[1]) | 24cfb8dRow pattern recognition patch (executor and commands).
6028 | 4 | ereport(ERROR, | 24cfb8dRow pattern recognition patch (executor and commands).
6029 | - | errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), | 24cfb8dRow pattern recognition patch (executor and commands).
6030 | - | errmsg("row pattern navigation offset must not be null")); | 24cfb8dRow pattern recognition patch (executor and commands).
6031 | - |  | 24cfb8dRow pattern recognition patch (executor and commands).
6032 | 9740 | val = DatumGetInt64(op->d.rpr_nav.offset_value[1]); | 24cfb8dRow pattern recognition patch (executor and commands).
6033 | - |  | 24cfb8dRow pattern recognition patch (executor and commands).
6034 | 9740 | if (val < 0) | 24cfb8dRow pattern recognition patch (executor and commands).
6035 | 4 | ereport(ERROR, | 24cfb8dRow pattern recognition patch (executor and commands).
6036 | - | errcode(ERRCODE_INVALID_PARAMETER_VALUE), | 24cfb8dRow pattern recognition patch (executor and commands).
6037 | - | errmsg("row pattern navigation offset must not be negative")); | 24cfb8dRow pattern recognition patch (executor and commands).
6038 | - |  | 24cfb8dRow pattern recognition patch (executor and commands).
6039 | 9736 | return val; | 24cfb8dRow pattern recognition patch (executor and commands).
6040 | - | } | 24cfb8dRow pattern recognition patch (executor and commands).

ExecEvalRPRNavSet() lines 6053-6220
Modified Lines Coverage: 52/60 lines (86.7%)

Line | Hits | Source | Commit
--- | --- | --- | ---
6053 | 984024 | ExecEvalRPRNavSet(ExprState *state, ExprEvalStep *op, ExprContext *econtext) | 24cfb8dRow pattern recognition patch (executor and commands).
6054 | - | { | 24cfb8dRow pattern recognition patch (executor and commands).
6055 | 984024 | WindowAggState *winstate = op->d.rpr_nav.winstate; | 24cfb8dRow pattern recognition patch (executor and commands).
6056 | 984024 | int64 offset; | 24cfb8dRow pattern recognition patch (executor and commands).
6057 | 984024 | int64 target_pos; | 24cfb8dRow pattern recognition patch (executor and commands).
6058 | 984024 | TupleTableSlot *target_slot; | 24cfb8dRow pattern recognition patch (executor and commands).
6059 | - |  | 24cfb8dRow pattern recognition patch (executor and commands).
6060 | - | /* Save current slot for later restore */ | 24cfb8dRow pattern recognition patch (executor and commands).
6061 | 984024 | winstate->nav_saved_outertuple = econtext->ecxt_outertuple; | 24cfb8dRow pattern recognition patch (executor and commands).
6062 | - |  | 24cfb8dRow pattern recognition patch (executor and commands).
6063 | - | /* | 24cfb8dRow pattern recognition patch (executor and commands).
6064 | - | * Determine the inner offset. NULL or negative offsets are errors per | 24cfb8dRow pattern recognition patch (executor and commands).
6065 | - | * the SQL standard. | 24cfb8dRow pattern recognition patch (executor and commands).
6066 | - | * | 24cfb8dRow pattern recognition patch (executor and commands).
6067 | - | * Default offset when offset_arg is NULL: PREV/NEXT: 1 (standard 5.6.2) | 24cfb8dRow pattern recognition patch (executor and commands).
6068 | - | * FIRST/LAST and compound: 0 for inner, 1 for outer | 24cfb8dRow pattern recognition patch (executor and commands).
6069 | - | */ | 24cfb8dRow pattern recognition patch (executor and commands).
6070 | 984024 | if (op->d.rpr_nav.offset_value != NULL) | 24cfb8dRow pattern recognition patch (executor and commands).
6071 | - | { | 24cfb8dRow pattern recognition patch (executor and commands).
6072 | 15844 | if (*op->d.rpr_nav.offset_isnull) | 24cfb8dRow pattern recognition patch (executor and commands).
6073 | 28 | ereport(ERROR, | 24cfb8dRow pattern recognition patch (executor and commands).
6074 | - | errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), | 24cfb8dRow pattern recognition patch (executor and commands).
6075 | - | errmsg("row pattern navigation offset must not be null")); | 24cfb8dRow pattern recognition patch (executor and commands).
6076 | - |  | 24cfb8dRow pattern recognition patch (executor and commands).
6077 | 15816 | offset = DatumGetInt64(*op->d.rpr_nav.offset_value); | 24cfb8dRow pattern recognition patch (executor and commands).
6078 | - |  | 24cfb8dRow pattern recognition patch (executor and commands).
6079 | 15816 | if (offset < 0) | 24cfb8dRow pattern recognition patch (executor and commands).
6080 | 24 | ereport(ERROR, | 24cfb8dRow pattern recognition patch (executor and commands).
6081 | - | errcode(ERRCODE_INVALID_PARAMETER_VALUE), | 24cfb8dRow pattern recognition patch (executor and commands).
6082 | - | errmsg("row pattern navigation offset must not be negative")); | 24cfb8dRow pattern recognition patch (executor and commands).
6083 | - | } | 24cfb8dRow pattern recognition patch (executor and commands).
6084 | - | else | 24cfb8dRow pattern recognition patch (executor and commands).
6085 | - | { | 24cfb8dRow pattern recognition patch (executor and commands).
6086 | - | /* Default offset: 1 for simple PREV/NEXT, 0 otherwise */ | 24cfb8dRow pattern recognition patch (executor and commands).
6087 | 968180 | if (op->d.rpr_nav.kind == RPR_NAV_PREV || | 24cfb8dRow pattern recognition patch (executor and commands).
6088 | - | op->d.rpr_nav.kind == RPR_NAV_NEXT) | 24cfb8dRow pattern recognition patch (executor and commands).
6089 | - | offset = 1; | 24cfb8dRow pattern recognition patch (executor and commands).
6090 | - | else | 24cfb8dRow pattern recognition patch (executor and commands).
6091 | 944 | offset = 0; | 24cfb8dRow pattern recognition patch (executor and commands).
6092 | - | } | 24cfb8dRow pattern recognition patch (executor and commands).
6093 | - |  | 24cfb8dRow pattern recognition patch (executor and commands).
6094 | - | /* | 24cfb8dRow pattern recognition patch (executor and commands).
6095 | - | * Calculate target position based on navigation direction. On overflow, | 24cfb8dRow pattern recognition patch (executor and commands).
6096 | - | * use -1 so that ExecRPRNavGetSlot treats it as out of range. | 24cfb8dRow pattern recognition patch (executor and commands).
6097 | - | */ | 24cfb8dRow pattern recognition patch (executor and commands).
6098 | 983972 | switch (op->d.rpr_nav.kind) | 24cfb8dRow pattern recognition patch (executor and commands).
6099 | - | { | 24cfb8dRow pattern recognition patch (executor and commands).
6100 | 972208 | case RPR_NAV_PREV: | 24cfb8dRow pattern recognition patch (executor and commands).
6101 | 972208 | if (pg_sub_s64_overflow(winstate->currentpos, offset, &target_pos)) | 24cfb8dRow pattern recognition patch (executor and commands).
6102 | 0 | target_pos = -1; | 24cfb8dRow pattern recognition patch (executor and commands).
6103 | - | break; | 24cfb8dRow pattern recognition patch (executor and commands).
6104 | 572 | case RPR_NAV_NEXT: | 24cfb8dRow pattern recognition patch (executor and commands).
6105 | 572 | if (pg_add_s64_overflow(winstate->currentpos, offset, &target_pos)) | 24cfb8dRow pattern recognition patch (executor and commands).
6106 | 0 | target_pos = -1; | 24cfb8dRow pattern recognition patch (executor and commands).
6107 | - | break; | 24cfb8dRow pattern recognition patch (executor and commands).
6108 | 628 | case RPR_NAV_FIRST: | 24cfb8dRow pattern recognition patch (executor and commands).
6109 | - | /* FIRST: offset from match_start, clamped to currentpos */ | 24cfb8dRow pattern recognition patch (executor and commands).
6110 | 628 | if (pg_add_s64_overflow(winstate->nav_match_start, offset, &target_pos)) | 24cfb8dRow pattern recognition patch (executor and commands).
6111 | - | target_pos = -1; | 24cfb8dRow pattern recognition patch (executor and commands).
6112 | 628 | else if (target_pos > winstate->currentpos) | 24cfb8dRow pattern recognition patch (executor and commands).
6113 | 68 | target_pos = -1; /* beyond current match range */ | 24cfb8dRow pattern recognition patch (executor and commands).
6114 | - | break; | 24cfb8dRow pattern recognition patch (executor and commands).
6115 | 580 | case RPR_NAV_LAST: | 24cfb8dRow pattern recognition patch (executor and commands).
6116 | - | /* LAST: offset backward from currentpos, clamped to match_start */ | 24cfb8dRow pattern recognition patch (executor and commands).
6117 | 580 | if (pg_sub_s64_overflow(winstate->currentpos, offset, &target_pos)) | 24cfb8dRow pattern recognition patch (executor and commands).
6118 | - | target_pos = -1; | 24cfb8dRow pattern recognition patch (executor and commands).
6119 | 580 | else if (target_pos < winstate->nav_match_start) | 24cfb8dRow pattern recognition patch (executor and commands).
6120 | 68 | target_pos = -1; /* before match_start */ | 24cfb8dRow pattern recognition patch (executor and commands).
6121 | - | break; | 24cfb8dRow pattern recognition patch (executor and commands).
6122 | - |  | 24cfb8dRow pattern recognition patch (executor and commands).
6123 | 9804 | case RPR_NAV_PREV_FIRST: | 24cfb8dRow pattern recognition patch (executor and commands).
6124 | - | case RPR_NAV_NEXT_FIRST: | 24cfb8dRow pattern recognition patch (executor and commands).
6125 | - | { | 24cfb8dRow pattern recognition patch (executor and commands).
6126 | 9804 | int64 compound_offset; | 24cfb8dRow pattern recognition patch (executor and commands).
6127 | 9804 | int64 inner_pos; | 24cfb8dRow pattern recognition patch (executor and commands).
6128 | - |  | 24cfb8dRow pattern recognition patch (executor and commands).
6129 | - | /* Inner: match_start + offset */ | 24cfb8dRow pattern recognition patch (executor and commands).
6130 | 9804 | if (pg_add_s64_overflow(winstate->nav_match_start, offset, &inner_pos)) | 24cfb8dRow pattern recognition patch (executor and commands).
6131 | - | { | 24cfb8dRow pattern recognition patch (executor and commands).
6132 | - | target_pos = -1; | 24cfb8dRow pattern recognition patch (executor and commands).
6133 | 983964 | break; | 24cfb8dRow pattern recognition patch (executor and commands).
6134 | - | } | 24cfb8dRow pattern recognition patch (executor and commands).
6135 | 9804 | if (inner_pos > winstate->currentpos || inner_pos < 0) | 24cfb8dRow pattern recognition patch (executor and commands).
6136 | - | { | 24cfb8dRow pattern recognition patch (executor and commands).
6137 | - | target_pos = -1; | 24cfb8dRow pattern recognition patch (executor and commands).
6138 | - | break; | 24cfb8dRow pattern recognition patch (executor and commands).
6139 | - | } | 24cfb8dRow pattern recognition patch (executor and commands).
6140 | - |  | 24cfb8dRow pattern recognition patch (executor and commands).
6141 | - | /* Outer offset */ | 24cfb8dRow pattern recognition patch (executor and commands).
6142 | 9672 | compound_offset = rpr_nav_get_compound_offset(op); | 24cfb8dRow pattern recognition patch (executor and commands).
6143 | - |  | 24cfb8dRow pattern recognition patch (executor and commands).
6144 | - | /* Apply outer: PREV subtracts, NEXT adds */ | 24cfb8dRow pattern recognition patch (executor and commands).
6145 | 9668 | if (op->d.rpr_nav.kind == RPR_NAV_PREV_FIRST) | 24cfb8dRow pattern recognition patch (executor and commands).
6146 | - | { | 24cfb8dRow pattern recognition patch (executor and commands).
6147 | 9564 | if (pg_sub_s64_overflow(inner_pos, compound_offset, &target_pos)) | 24cfb8dRow pattern recognition patch (executor and commands).
6148 | 0 | target_pos = -1; | 24cfb8dRow pattern recognition patch (executor and commands).
6149 | - | } | 24cfb8dRow pattern recognition patch (executor and commands).
6150 | - | else | 24cfb8dRow pattern recognition patch (executor and commands).
6151 | - | { | 24cfb8dRow pattern recognition patch (executor and commands).
6152 | 104 | if (pg_add_s64_overflow(inner_pos, compound_offset, &target_pos)) | 24cfb8dRow pattern recognition patch (executor and commands).
6153 | 0 | target_pos = -1; | 24cfb8dRow pattern recognition patch (executor and commands).
6154 | - | } | 24cfb8dRow pattern recognition patch (executor and commands).
6155 | - | } | 24cfb8dRow pattern recognition patch (executor and commands).
6156 | - | break; | 24cfb8dRow pattern recognition patch (executor and commands).
6157 | - |  | 24cfb8dRow pattern recognition patch (executor and commands).
6158 | 180 | case RPR_NAV_PREV_LAST: | 24cfb8dRow pattern recognition patch (executor and commands).
6159 | - | case RPR_NAV_NEXT_LAST: | 24cfb8dRow pattern recognition patch (executor and commands).
6160 | - | { | 24cfb8dRow pattern recognition patch (executor and commands).
6161 | 180 | int64 compound_offset; | 24cfb8dRow pattern recognition patch (executor and commands).
6162 | 180 | int64 inner_pos; | 24cfb8dRow pattern recognition patch (executor and commands).
6163 | - |  | 24cfb8dRow pattern recognition patch (executor and commands).
6164 | - | /* Inner: currentpos - offset */ | 24cfb8dRow pattern recognition patch (executor and commands).
6165 | 180 | if (pg_sub_s64_overflow(winstate->currentpos, offset, &inner_pos)) | 24cfb8dRow pattern recognition patch (executor and commands).
6166 | - | { | 24cfb8dRow pattern recognition patch (executor and commands).
6167 | - | target_pos = -1; | 24cfb8dRow pattern recognition patch (executor and commands).
6168 | 983964 | break; | 24cfb8dRow pattern recognition patch (executor and commands).
6169 | - | } | 24cfb8dRow pattern recognition patch (executor and commands).
6170 | 180 | if (inner_pos < winstate->nav_match_start) | 24cfb8dRow pattern recognition patch (executor and commands).
6171 | - | { | 24cfb8dRow pattern recognition patch (executor and commands).
6172 | - | target_pos = -1; | 24cfb8dRow pattern recognition patch (executor and commands).
6173 | - | break; | 24cfb8dRow pattern recognition patch (executor and commands).
6174 | - | } | 24cfb8dRow pattern recognition patch (executor and commands).
6175 | - |  | 24cfb8dRow pattern recognition patch (executor and commands).
6176 | - | /* Outer offset */ | 24cfb8dRow pattern recognition patch (executor and commands).
6177 | 72 | compound_offset = rpr_nav_get_compound_offset(op); | 24cfb8dRow pattern recognition patch (executor and commands).
6178 | - |  | 24cfb8dRow pattern recognition patch (executor and commands).
6179 | - | /* Apply outer: PREV subtracts, NEXT adds */ | 24cfb8dRow pattern recognition patch (executor and commands).
6180 | 68 | if (op->d.rpr_nav.kind == RPR_NAV_PREV_LAST) | 24cfb8dRow pattern recognition patch (executor and commands).
6181 | - | { | 24cfb8dRow pattern recognition patch (executor and commands).
6182 | 24 | if (pg_sub_s64_overflow(inner_pos, compound_offset, &target_pos)) | 24cfb8dRow pattern recognition patch (executor and commands).
6183 | 0 | target_pos = -1; | 24cfb8dRow pattern recognition patch (executor and commands).
6184 | - | } | 24cfb8dRow pattern recognition patch (executor and commands).
6185 | - | else | 24cfb8dRow pattern recognition patch (executor and commands).
6186 | - | { | 24cfb8dRow pattern recognition patch (executor and commands).
6187 | 44 | if (pg_add_s64_overflow(inner_pos, compound_offset, &target_pos)) | 24cfb8dRow pattern recognition patch (executor and commands).
6188 | 0 | target_pos = -1; | 24cfb8dRow pattern recognition patch (executor and commands).
6189 | - | } | 24cfb8dRow pattern recognition patch (executor and commands).
6190 | - | } | 24cfb8dRow pattern recognition patch (executor and commands).
6191 | - | break; | 24cfb8dRow pattern recognition patch (executor and commands).
6192 | 0 | default: | 24cfb8dRow pattern recognition patch (executor and commands).
6193 | 0 | elog(ERROR, "unrecognized RPR navigation kind: %d", | 24cfb8dRow pattern recognition patch (executor and commands).
6194 | - | op->d.rpr_nav.kind); | 24cfb8dRow pattern recognition patch (executor and commands).
6195 | - | break; | 24cfb8dRow pattern recognition patch (executor and commands).
6196 | - | } | 24cfb8dRow pattern recognition patch (executor and commands).
6197 | - |  | 24cfb8dRow pattern recognition patch (executor and commands).
6198 | - | /* | 24cfb8dRow pattern recognition patch (executor and commands).
6199 | - | * Slot swap elision: if target_pos is the current row, skip the | 24cfb8dRow pattern recognition patch (executor and commands).
6200 | - | * tuplestore fetch and slot swap entirely. This benefits LAST(expr), | 24cfb8dRow pattern recognition patch (executor and commands).
6201 | - | * PREV(expr, 0), NEXT(expr, 0), and similar cases. | 24cfb8dRow pattern recognition patch (executor and commands).
6202 | - | * | 24cfb8dRow pattern recognition patch (executor and commands).
6203 | - | * We must still set nav_saved_outertuple (done above) so that | 24cfb8dRow pattern recognition patch (executor and commands).
6204 | - | * EEOP_RPR_NAV_RESTORE is a harmless no-op. | 24cfb8dRow pattern recognition patch (executor and commands).
6205 | - | */ | 24cfb8dRow pattern recognition patch (executor and commands).
6206 | 983964 | if (target_pos == winstate->currentpos) | 24cfb8dRow pattern recognition patch (executor and commands).
6207 | 983964 | return; | 24cfb8dRow pattern recognition patch (executor and commands).
6208 | - |  | 24cfb8dRow pattern recognition patch (executor and commands).
6209 | - | /* Fetch target row slot (returns nav_null_slot if out of range) */ | 24cfb8dRow pattern recognition patch (executor and commands).
6210 | 983092 | target_slot = ExecRPRNavGetSlot(winstate, target_pos); | 24cfb8dRow pattern recognition patch (executor and commands).
6211 | - |  | 24cfb8dRow pattern recognition patch (executor and commands).
6212 | - | /* | 24cfb8dRow pattern recognition patch (executor and commands).
6213 | - | * Update econtext to point to the target slot. Also decompress the new | 24cfb8dRow pattern recognition patch (executor and commands).
6214 | - | * slot's attributes since FETCHSOME already ran for the original slot. | 24cfb8dRow pattern recognition patch (executor and commands).
6215 | - | * The caller (interpreter or JIT) is responsible for updating any local | 24cfb8dRow pattern recognition patch (executor and commands).
6216 | - | * slot cache (e.g. outerslot) from econtext after we return. | 24cfb8dRow pattern recognition patch (executor and commands).
6217 | - | */ | 24cfb8dRow pattern recognition patch (executor and commands).
6218 | 983092 | slot_getallattrs(target_slot); | 24cfb8dRow pattern recognition patch (executor and commands).
6219 | 983092 | econtext->ecxt_outertuple = target_slot; | 24cfb8dRow pattern recognition patch (executor and commands).
6220 | - | } | 24cfb8dRow pattern recognition patch (executor and commands).

ExecEvalRPRNavRestore() lines 6238-6257
Modified Lines Coverage: 11/11 lines (100.0%)

Line | Hits | Source | Commit
--- | --- | --- | ---
6238 | 983964 | ExecEvalRPRNavRestore(ExprState *state, ExprEvalStep *op, | 24cfb8dRow pattern recognition patch (executor and commands).
6239 | - | ExprContext *econtext) | 24cfb8dRow pattern recognition patch (executor and commands).
6240 | - | { | 24cfb8dRow pattern recognition patch (executor and commands).
6241 | 983964 | WindowAggState *winstate = op->d.rpr_nav.winstate; | 24cfb8dRow pattern recognition patch (executor and commands).
6242 | - |  | 24cfb8dRow pattern recognition patch (executor and commands).
6243 | 983964 | econtext->ecxt_outertuple = winstate->nav_saved_outertuple; | 24cfb8dRow pattern recognition patch (executor and commands).
6244 | - |  | 24cfb8dRow pattern recognition patch (executor and commands).
6245 | - | /* Stabilize pass-by-ref result against nav_slot re-fetch */ | 24cfb8dRow pattern recognition patch (executor and commands).
6246 | 983964 | if (!op->d.rpr_nav.resulttypbyval && | 24cfb8dRow pattern recognition patch (executor and commands).
6247 | 144604 | !*op->resnull) | 24cfb8dRow pattern recognition patch (executor and commands).
6248 | - | { | 24cfb8dRow pattern recognition patch (executor and commands).
6249 | 130112 | MemoryContext oldContext; | 24cfb8dRow pattern recognition patch (executor and commands).
6250 | - |  | 24cfb8dRow pattern recognition patch (executor and commands).
6251 | 130112 | oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory); | 24cfb8dRow pattern recognition patch (executor and commands).
6252 | 260224 | *op->resvalue = datumCopy(*op->resvalue, | 24cfb8dRow pattern recognition patch (executor and commands).
6253 | - | false, | 24cfb8dRow pattern recognition patch (executor and commands).
6254 | 130112 | op->d.rpr_nav.resulttyplen); | 24cfb8dRow pattern recognition patch (executor and commands).
6255 | 130112 | MemoryContextSwitchTo(oldContext); | 24cfb8dRow pattern recognition patch (executor and commands).
6256 | - | } | 24cfb8dRow pattern recognition patch (executor and commands).
6257 | 983964 | } | 24cfb8dRow pattern recognition patch (executor and commands).