| Line | Hits | Source | Commit |
| 510 |
- |
transformColumnRef(ParseState *pstate, ColumnRef *cref) |
- |
| 511 |
- |
{ |
- |
| 512 |
- |
Node *node = NULL; |
- |
| 513 |
- |
char *nspname = NULL; |
- |
| 514 |
- |
char *relname = NULL; |
- |
| 515 |
- |
char *colname = NULL; |
- |
| 516 |
- |
ParseNamespaceItem *nsitem; |
- |
| 517 |
- |
int levels_up; |
- |
| 518 |
- |
enum |
- |
| 519 |
- |
{ |
- |
| 520 |
- |
CRERR_NO_COLUMN, |
- |
| 521 |
- |
CRERR_NO_RTE, |
- |
| 522 |
- |
CRERR_WRONG_DB, |
- |
| 523 |
- |
CRERR_TOO_MANY |
- |
| 524 |
- |
} crerr = CRERR_NO_COLUMN; |
- |
| 525 |
- |
const char *err; |
- |
| 526 |
- |
|
- |
| 527 |
- |
/* |
- |
| 528 |
- |
* Check to see if the column reference is in an invalid place within the |
- |
| 529 |
- |
* query. We allow column references in most places, except in default |
- |
| 530 |
- |
* expressions and partition bound expressions. |
- |
| 531 |
- |
*/ |
- |
| 532 |
- |
err = NULL; |
- |
| 533 |
- |
switch (pstate->p_expr_kind) |
- |
| 534 |
- |
{ |
- |
| 535 |
- |
case EXPR_KIND_NONE: |
- |
| 536 |
- |
Assert(false); /* can't happen */ |
- |
| 537 |
- |
break; |
- |
| 538 |
- |
case EXPR_KIND_OTHER: |
- |
| 539 |
- |
case EXPR_KIND_JOIN_ON: |
- |
| 540 |
- |
case EXPR_KIND_JOIN_USING: |
- |
| 541 |
- |
case EXPR_KIND_FROM_SUBSELECT: |
- |
| 542 |
- |
case EXPR_KIND_FROM_FUNCTION: |
- |
| 543 |
- |
case EXPR_KIND_WHERE: |
- |
| 544 |
- |
case EXPR_KIND_POLICY: |
- |
| 545 |
- |
case EXPR_KIND_HAVING: |
- |
| 546 |
- |
case EXPR_KIND_FILTER: |
- |
| 547 |
- |
case EXPR_KIND_WINDOW_PARTITION: |
- |
| 548 |
- |
case EXPR_KIND_WINDOW_ORDER: |
- |
| 549 |
- |
case EXPR_KIND_WINDOW_FRAME_RANGE: |
- |
| 550 |
- |
case EXPR_KIND_WINDOW_FRAME_ROWS: |
- |
| 551 |
- |
case EXPR_KIND_WINDOW_FRAME_GROUPS: |
- |
| 552 |
- |
case EXPR_KIND_SELECT_TARGET: |
- |
| 553 |
- |
case EXPR_KIND_INSERT_TARGET: |
- |
| 554 |
- |
case EXPR_KIND_UPDATE_SOURCE: |
- |
| 555 |
- |
case EXPR_KIND_UPDATE_TARGET: |
- |
| 556 |
- |
case EXPR_KIND_MERGE_WHEN: |
- |
| 557 |
- |
case EXPR_KIND_GROUP_BY: |
- |
| 558 |
- |
case EXPR_KIND_ORDER_BY: |
- |
| 559 |
- |
case EXPR_KIND_DISTINCT_ON: |
- |
| 560 |
- |
case EXPR_KIND_LIMIT: |
- |
| 561 |
- |
case EXPR_KIND_OFFSET: |
- |
| 562 |
- |
case EXPR_KIND_RETURNING: |
- |
| 563 |
- |
case EXPR_KIND_MERGE_RETURNING: |
- |
| 564 |
- |
case EXPR_KIND_VALUES: |
- |
| 565 |
- |
case EXPR_KIND_VALUES_SINGLE: |
- |
| 566 |
- |
case EXPR_KIND_CHECK_CONSTRAINT: |
- |
| 567 |
- |
case EXPR_KIND_DOMAIN_CHECK: |
- |
| 568 |
- |
case EXPR_KIND_FUNCTION_DEFAULT: |
- |
| 569 |
- |
case EXPR_KIND_INDEX_EXPRESSION: |
- |
| 570 |
- |
case EXPR_KIND_INDEX_PREDICATE: |
- |
| 571 |
- |
case EXPR_KIND_STATS_EXPRESSION: |
- |
| 572 |
- |
case EXPR_KIND_ALTER_COL_TRANSFORM: |
- |
| 573 |
- |
case EXPR_KIND_EXECUTE_PARAMETER: |
- |
| 574 |
- |
case EXPR_KIND_TRIGGER_WHEN: |
- |
| 575 |
- |
case EXPR_KIND_PARTITION_EXPRESSION: |
- |
| 576 |
- |
case EXPR_KIND_CALL_ARGUMENT: |
- |
| 577 |
- |
case EXPR_KIND_COPY_WHERE: |
- |
| 578 |
- |
case EXPR_KIND_GENERATED_COLUMN: |
- |
| 579 |
- |
case EXPR_KIND_CYCLE_MARK: |
- |
| 580 |
- |
case EXPR_KIND_PROPGRAPH_PROPERTY: |
86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 581 |
- |
/* okay */ |
- |
| 582 |
- |
break; |
- |
| 583 |
- |
|
- |
| 584 |
- |
case EXPR_KIND_COLUMN_DEFAULT: |
- |
| 585 |
- |
err = _("cannot use column reference in DEFAULT expression"); |
- |
| 586 |
- |
break; |
- |
| 587 |
- |
case EXPR_KIND_PARTITION_BOUND: |
- |
| 588 |
- |
err = _("cannot use column reference in partition bound expression"); |
- |
| 589 |
- |
break; |
- |
| 590 |
- |
|
- |
| 591 |
- |
/* |
- |
| 592 |
- |
* There is intentionally no default: case here, so that the |
- |
| 593 |
- |
* compiler will warn if we add a new ParseExprKind without |
- |
| 594 |
- |
* extending this switch. If we do see an unrecognized value at |
- |
| 595 |
- |
* runtime, the behavior will be the same as for EXPR_KIND_OTHER, |
- |
| 596 |
- |
* which is sane anyway. |
- |
| 597 |
- |
*/ |
- |
| 598 |
- |
} |
- |
| 599 |
- |
if (err) |
- |
| 600 |
- |
ereport(ERROR, |
- |
| 601 |
- |
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
- |
| 602 |
- |
errmsg_internal("%s", err), |
- |
| 603 |
- |
parser_errposition(pstate, cref->location))); |
- |
| 604 |
- |
|
- |
| 605 |
- |
/* |
- |
| 606 |
- |
* Give the PreParseColumnRefHook, if any, first shot. If it returns |
- |
| 607 |
- |
* non-null then that's all, folks. |
- |
| 608 |
- |
*/ |
- |
| 609 |
- |
if (pstate->p_pre_columnref_hook != NULL) |
- |
| 610 |
- |
{ |
- |
| 611 |
- |
node = pstate->p_pre_columnref_hook(pstate, cref); |
- |
| 612 |
- |
if (node != NULL) |
- |
| 613 |
- |
return node; |
- |
| 614 |
- |
} |
- |
| 615 |
- |
|
- |
| 616 |
- |
/*---------- |
- |
| 617 |
- |
* The allowed syntaxes are: |
- |
| 618 |
- |
* |
- |
| 619 |
- |
* A First try to resolve as unqualified column name; |
- |
| 620 |
- |
* if no luck, try to resolve as unqualified table name (A.*). |
- |
| 621 |
- |
* A.B A is an unqualified table name; B is either a |
- |
| 622 |
- |
* column or function name (trying column name first). |
- |
| 623 |
- |
* A.B.C schema A, table B, col or func name C. |
- |
| 624 |
- |
* A.B.C.D catalog A, schema B, table C, col or func D. |
- |
| 625 |
- |
* A.* A is an unqualified table name; means whole-row value. |
- |
| 626 |
- |
* A.B.* whole-row value of table B in schema A. |
- |
| 627 |
- |
* A.B.C.* whole-row value of table C in schema B in catalog A. |
- |
| 628 |
- |
* |
- |
| 629 |
- |
* We do not need to cope with bare "*"; that will only be accepted by |
- |
| 630 |
- |
* the grammar at the top level of a SELECT list, and transformTargetList |
- |
| 631 |
- |
* will take care of it before it ever gets here. Also, "A.*" etc will |
- |
| 632 |
- |
* be expanded by transformTargetList if they appear at SELECT top level, |
- |
| 633 |
- |
* so here we are only going to see them as function or operator inputs. |
- |
| 634 |
- |
* |
- |
| 635 |
- |
* Currently, if a catalog name is given then it must equal the current |
- |
| 636 |
- |
* database name; we check it here and then discard it. |
- |
| 637 |
- |
*---------- |
- |
| 638 |
- |
*/ |
- |
| 639 |
- |
switch (list_length(cref->fields)) |
- |
| 640 |
- |
{ |
- |
| 641 |
- |
case 1: |
- |
| 642 |
- |
{ |
- |
| 643 |
- |
Node *field1 = (Node *) linitial(cref->fields); |
- |
| 644 |
- |
|
- |
| 645 |
- |
colname = strVal(field1); |
- |
| 646 |
- |
|
- |
| 647 |
- |
/* Try to identify as an unqualified column */ |
- |
| 648 |
- |
node = colNameToVar(pstate, colname, false, cref->location); |
- |
| 649 |
- |
|
- |
| 650 |
- |
if (node == NULL) |
- |
| 651 |
- |
{ |
- |
| 652 |
- |
/* |
- |
| 653 |
- |
* Not known as a column of any range-table entry. |
- |
| 654 |
- |
* |
- |
| 655 |
- |
* Try to find the name as a relation. Note that only |
- |
| 656 |
- |
* relations already entered into the rangetable will be |
- |
| 657 |
- |
* recognized. |
- |
| 658 |
- |
* |
- |
| 659 |
- |
* This is a hack for backwards compatibility with |
- |
| 660 |
- |
* PostQUEL-inspired syntax. The preferred form now is |
- |
| 661 |
- |
* "rel.*". |
- |
| 662 |
- |
*/ |
- |
| 663 |
- |
nsitem = refnameNamespaceItem(pstate, NULL, colname, |
- |
| 664 |
- |
cref->location, |
- |
| 665 |
- |
&levels_up); |
- |
| 666 |
- |
if (nsitem) |
- |
| 667 |
- |
node = transformWholeRowRef(pstate, nsitem, levels_up, |
- |
| 668 |
- |
cref->location); |
- |
| 669 |
- |
} |
- |
| 670 |
- |
break; |
- |
| 671 |
- |
} |
- |
| 672 |
- |
case 2: |
- |
| 673 |
- |
{ |
- |
| 674 |
- |
Node *field1 = (Node *) linitial(cref->fields); |
- |
| 675 |
- |
Node *field2 = (Node *) lsecond(cref->fields); |
- |
| 676 |
- |
|
- |
| 677 |
- |
relname = strVal(field1); |
- |
| 678 |
- |
|
- |
| 679 |
- |
/* Locate the referenced nsitem */ |
- |
| 680 |
- |
nsitem = refnameNamespaceItem(pstate, nspname, relname, |
- |
| 681 |
- |
cref->location, |
- |
| 682 |
- |
&levels_up); |
- |
| 683 |
- |
if (nsitem == NULL) |
- |
| 684 |
- |
{ |
- |
| 685 |
- |
crerr = CRERR_NO_RTE; |
- |
| 686 |
- |
break; |
- |
| 687 |
- |
} |
- |
| 688 |
- |
|
- |
| 689 |
- |
/* Whole-row reference? */ |
- |
| 690 |
- |
if (IsA(field2, A_Star)) |
- |
| 691 |
- |
{ |
- |
| 692 |
- |
node = transformWholeRowRef(pstate, nsitem, levels_up, |
- |
| 693 |
- |
cref->location); |
- |
| 694 |
- |
break; |
- |
| 695 |
- |
} |
- |
| 696 |
- |
|
- |
| 697 |
- |
colname = strVal(field2); |
- |
| 698 |
- |
|
- |
| 699 |
- |
/* Try to identify as a column of the nsitem */ |
- |
| 700 |
- |
node = scanNSItemForColumn(pstate, nsitem, levels_up, colname, |
- |
| 701 |
- |
cref->location); |
- |
| 702 |
- |
if (node == NULL) |
- |
| 703 |
- |
{ |
- |
| 704 |
- |
/* Try it as a function call on the whole row */ |
- |
| 705 |
- |
node = transformWholeRowRef(pstate, nsitem, levels_up, |
- |
| 706 |
- |
cref->location); |
- |
| 707 |
- |
node = ParseFuncOrColumn(pstate, |
- |
| 708 |
- |
list_make1(makeString(colname)), |
- |
| 709 |
- |
list_make1(node), |
- |
| 710 |
- |
pstate->p_last_srf, |
- |
| 711 |
- |
NULL, |
- |
| 712 |
- |
false, |
- |
| 713 |
- |
cref->location); |
- |
| 714 |
- |
} |
- |
| 715 |
- |
break; |
- |
| 716 |
- |
} |
- |
| 717 |
- |
case 3: |
- |
| 718 |
- |
{ |
- |
| 719 |
- |
Node *field1 = (Node *) linitial(cref->fields); |
- |
| 720 |
- |
Node *field2 = (Node *) lsecond(cref->fields); |
- |
| 721 |
- |
Node *field3 = (Node *) lthird(cref->fields); |
- |
| 722 |
- |
|
- |
| 723 |
- |
nspname = strVal(field1); |
- |
| 724 |
- |
relname = strVal(field2); |
- |
| 725 |
- |
|
- |
| 726 |
- |
/* Locate the referenced nsitem */ |
- |
| 727 |
- |
nsitem = refnameNamespaceItem(pstate, nspname, relname, |
- |
| 728 |
- |
cref->location, |
- |
| 729 |
- |
&levels_up); |
- |
| 730 |
- |
if (nsitem == NULL) |
- |
| 731 |
- |
{ |
- |
| 732 |
- |
crerr = CRERR_NO_RTE; |
- |
| 733 |
- |
break; |
- |
| 734 |
- |
} |
- |
| 735 |
- |
|
- |
| 736 |
- |
/* Whole-row reference? */ |
- |
| 737 |
- |
if (IsA(field3, A_Star)) |
- |
| 738 |
- |
{ |
- |
| 739 |
- |
node = transformWholeRowRef(pstate, nsitem, levels_up, |
- |
| 740 |
- |
cref->location); |
- |
| 741 |
- |
break; |
- |
| 742 |
- |
} |
- |
| 743 |
- |
|
- |
| 744 |
- |
colname = strVal(field3); |
- |
| 745 |
- |
|
- |
| 746 |
- |
/* Try to identify as a column of the nsitem */ |
- |
| 747 |
- |
node = scanNSItemForColumn(pstate, nsitem, levels_up, colname, |
- |
| 748 |
- |
cref->location); |
- |
| 749 |
- |
if (node == NULL) |
- |
| 750 |
- |
{ |
- |
| 751 |
- |
/* Try it as a function call on the whole row */ |
- |
| 752 |
- |
node = transformWholeRowRef(pstate, nsitem, levels_up, |
- |
| 753 |
- |
cref->location); |
- |
| 754 |
- |
node = ParseFuncOrColumn(pstate, |
- |
| 755 |
- |
list_make1(makeString(colname)), |
- |
| 756 |
- |
list_make1(node), |
- |
| 757 |
- |
pstate->p_last_srf, |
- |
| 758 |
- |
NULL, |
- |
| 759 |
- |
false, |
- |
| 760 |
- |
cref->location); |
- |
| 761 |
- |
} |
- |
| 762 |
- |
break; |
- |
| 763 |
- |
} |
- |
| 764 |
- |
case 4: |
- |
| 765 |
- |
{ |
- |
| 766 |
- |
Node *field1 = (Node *) linitial(cref->fields); |
- |
| 767 |
- |
Node *field2 = (Node *) lsecond(cref->fields); |
- |
| 768 |
- |
Node *field3 = (Node *) lthird(cref->fields); |
- |
| 769 |
- |
Node *field4 = (Node *) lfourth(cref->fields); |
- |
| 770 |
- |
char *catname; |
- |
| 771 |
- |
|
- |
| 772 |
- |
catname = strVal(field1); |
- |
| 773 |
- |
nspname = strVal(field2); |
- |
| 774 |
- |
relname = strVal(field3); |
- |
| 775 |
- |
|
- |
| 776 |
- |
/* |
- |
| 777 |
- |
* We check the catalog name and then ignore it. |
- |
| 778 |
- |
*/ |
- |
| 779 |
- |
if (strcmp(catname, get_database_name(MyDatabaseId)) != 0) |
- |
| 780 |
- |
{ |
- |
| 781 |
- |
crerr = CRERR_WRONG_DB; |
- |
| 782 |
- |
break; |
- |
| 783 |
- |
} |
- |
| 784 |
- |
|
- |
| 785 |
- |
/* Locate the referenced nsitem */ |
- |
| 786 |
- |
nsitem = refnameNamespaceItem(pstate, nspname, relname, |
- |
| 787 |
- |
cref->location, |
- |
| 788 |
- |
&levels_up); |
- |
| 789 |
- |
if (nsitem == NULL) |
- |
| 790 |
- |
{ |
- |
| 791 |
- |
crerr = CRERR_NO_RTE; |
- |
| 792 |
- |
break; |
- |
| 793 |
- |
} |
- |
| 794 |
- |
|
- |
| 795 |
- |
/* Whole-row reference? */ |
- |
| 796 |
- |
if (IsA(field4, A_Star)) |
- |
| 797 |
- |
{ |
- |
| 798 |
- |
node = transformWholeRowRef(pstate, nsitem, levels_up, |
- |
| 799 |
- |
cref->location); |
- |
| 800 |
- |
break; |
- |
| 801 |
- |
} |
- |
| 802 |
- |
|
- |
| 803 |
- |
colname = strVal(field4); |
- |
| 804 |
- |
|
- |
| 805 |
- |
/* Try to identify as a column of the nsitem */ |
- |
| 806 |
- |
node = scanNSItemForColumn(pstate, nsitem, levels_up, colname, |
- |
| 807 |
- |
cref->location); |
- |
| 808 |
- |
if (node == NULL) |
- |
| 809 |
- |
{ |
- |
| 810 |
- |
/* Try it as a function call on the whole row */ |
- |
| 811 |
- |
node = transformWholeRowRef(pstate, nsitem, levels_up, |
- |
| 812 |
- |
cref->location); |
- |
| 813 |
- |
node = ParseFuncOrColumn(pstate, |
- |
| 814 |
- |
list_make1(makeString(colname)), |
- |
| 815 |
- |
list_make1(node), |
- |
| 816 |
- |
pstate->p_last_srf, |
- |
| 817 |
- |
NULL, |
- |
| 818 |
- |
false, |
- |
| 819 |
- |
cref->location); |
- |
| 820 |
- |
} |
- |
| 821 |
- |
break; |
- |
| 822 |
- |
} |
- |
| 823 |
- |
default: |
- |
| 824 |
- |
crerr = CRERR_TOO_MANY; /* too many dotted names */ |
- |
| 825 |
- |
break; |
- |
| 826 |
- |
} |
- |
| 827 |
- |
|
- |
| 828 |
- |
/* Try it as a graph table property reference. */ |
86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 829 |
919107 |
if (node == NULL) |
86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 830 |
19173 |
node = transformGraphTablePropertyRef(pstate, cref); |
86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 831 |
- |
|
86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 832 |
- |
/* |
- |
| 833 |
- |
* Now give the PostParseColumnRefHook, if any, a chance. We pass the |
- |
| 834 |
- |
* translation-so-far so that it can throw an error if it wishes in the |
- |
| 835 |
- |
* case that it has a conflicting interpretation of the ColumnRef. (If it |
- |
| 836 |
- |
* just translates anyway, we'll throw an error, because we can't undo |
- |
| 837 |
- |
* whatever effects the preceding steps may have had on the pstate.) If it |
- |
| 838 |
- |
* returns NULL, use the standard translation, or throw a suitable error |
- |
| 839 |
- |
* if there is none. |
- |
| 840 |
- |
*/ |
- |
| 841 |
- |
if (pstate->p_post_columnref_hook != NULL) |
- |
| 842 |
- |
{ |
- |
| 843 |
- |
Node *hookresult; |
- |
| 844 |
- |
|
- |
| 845 |
- |
hookresult = pstate->p_post_columnref_hook(pstate, cref, node); |
- |
| 846 |
- |
if (node == NULL) |
- |
| 847 |
- |
node = hookresult; |
- |
| 848 |
- |
else if (hookresult != NULL) |
- |
| 849 |
- |
ereport(ERROR, |
- |
| 850 |
- |
(errcode(ERRCODE_AMBIGUOUS_COLUMN), |
- |
| 851 |
- |
errmsg("column reference \"%s\" is ambiguous", |
- |
| 852 |
- |
NameListToString(cref->fields)), |
- |
| 853 |
- |
parser_errposition(pstate, cref->location))); |
- |
| 854 |
- |
} |
- |
| 855 |
- |
|
- |
| 856 |
- |
/* |
- |
| 857 |
- |
* Throw error if no translation found. |
- |
| 858 |
- |
*/ |
- |
| 859 |
- |
if (node == NULL) |
- |
| 860 |
- |
{ |
- |
| 861 |
- |
switch (crerr) |
- |
| 862 |
- |
{ |
- |
| 863 |
- |
case CRERR_NO_COLUMN: |
- |
| 864 |
- |
errorMissingColumn(pstate, relname, colname, cref->location); |
- |
| 865 |
- |
break; |
- |
| 866 |
- |
case CRERR_NO_RTE: |
- |
| 867 |
- |
errorMissingRTE(pstate, makeRangeVar(nspname, relname, |
- |
| 868 |
- |
cref->location)); |
- |
| 869 |
- |
break; |
- |
| 870 |
- |
case CRERR_WRONG_DB: |
- |
| 871 |
- |
ereport(ERROR, |
- |
| 872 |
- |
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
- |
| 873 |
- |
errmsg("cross-database references are not implemented: %s", |
- |
| 874 |
- |
NameListToString(cref->fields)), |
- |
| 875 |
- |
parser_errposition(pstate, cref->location))); |
- |
| 876 |
- |
break; |
- |
| 877 |
- |
case CRERR_TOO_MANY: |
- |
| 878 |
- |
ereport(ERROR, |
- |
| 879 |
- |
(errcode(ERRCODE_SYNTAX_ERROR), |
- |
| 880 |
- |
errmsg("improper qualified name (too many dotted names): %s", |
- |
| 881 |
- |
NameListToString(cref->fields)), |
- |
| 882 |
- |
parser_errposition(pstate, cref->location))); |
- |
| 883 |
- |
break; |
- |
| 884 |
- |
} |
- |
| 885 |
- |
} |
- |
| 886 |
- |
|
- |
| 887 |
- |
return node; |
- |
| 888 |
- |
} |
- |