|
18 | 18 | #include "access/htup_details.h" |
19 | 19 | #include "catalog/pg_aggregate.h" |
20 | 20 | #include "catalog/pg_type.h" |
| 21 | +#include "commands/session_variable.h" |
21 | 22 | #include "miscadmin.h" |
22 | 23 | #include "nodes/makefuncs.h" |
23 | 24 | #include "nodes/nodeFuncs.h" |
@@ -77,6 +78,7 @@ static Node *transformWholeRowRef(ParseState *pstate, |
77 | 78 | static Node *transformIndirection(ParseState *pstate, A_Indirection *ind); |
78 | 79 | static Node *transformTypeCast(ParseState *pstate, TypeCast *tc); |
79 | 80 | static Node *transformCollateClause(ParseState *pstate, CollateClause *c); |
| 81 | +static Node *transformVariableFence(ParseState *pstate, VariableFence *vf); |
80 | 82 | static Node *transformJsonObjectConstructor(ParseState *pstate, |
81 | 83 | JsonObjectConstructor *ctor); |
82 | 84 | static Node *transformJsonArrayConstructor(ParseState *pstate, |
@@ -371,6 +373,10 @@ transformExprRecurse(ParseState *pstate, Node *expr) |
371 | 373 | result = transformJsonFuncExpr(pstate, (JsonFuncExpr *) expr); |
372 | 374 | break; |
373 | 375 |
|
| 376 | + case T_VariableFence: |
| 377 | + result = transformVariableFence(pstate, (VariableFence *) expr); |
| 378 | + break; |
| 379 | + |
374 | 380 | default: |
375 | 381 | /* should not reach here */ |
376 | 382 | elog(ERROR, "unrecognized node type: %d", (int) nodeTag(expr)); |
@@ -904,6 +910,119 @@ transformParamRef(ParseState *pstate, ParamRef *pref) |
904 | 910 | return result; |
905 | 911 | } |
906 | 912 |
|
| 913 | +/* |
| 914 | + * Returns true if the given expression kind is valid for session variables. |
| 915 | + * Session variables can be used everywhere where external parameters can be |
| 916 | + * used. Session variables are not allowed in DDL commands or in constraints. |
| 917 | + * |
| 918 | + * An identifier can be parsed as a session variable only for expression kinds |
| 919 | + * where session variables are allowed. This is the primary usage of this |
| 920 | + * function. |
| 921 | + * |
| 922 | + * The second usage of this function is to decide whether a "column does not |
| 923 | + * exist" or a "column or variable does not exist" error message should be |
| 924 | + * printed. When we are in an expression where session variables cannot be |
| 925 | + * used, we raise the first form of error message. |
| 926 | + */ |
| 927 | +static bool |
| 928 | +expr_kind_allows_session_variables(ParseExprKind p_expr_kind) |
| 929 | +{ |
| 930 | + bool result = false; |
| 931 | + |
| 932 | + switch (p_expr_kind) |
| 933 | + { |
| 934 | + case EXPR_KIND_NONE: |
| 935 | + Assert(false); /* can't happen */ |
| 936 | + return false; |
| 937 | + |
| 938 | + /* session variables allowed */ |
| 939 | + case EXPR_KIND_OTHER: |
| 940 | + case EXPR_KIND_JOIN_ON: |
| 941 | + case EXPR_KIND_FROM_SUBSELECT: |
| 942 | + case EXPR_KIND_FROM_FUNCTION: |
| 943 | + case EXPR_KIND_WHERE: |
| 944 | + case EXPR_KIND_HAVING: |
| 945 | + case EXPR_KIND_FILTER: |
| 946 | + case EXPR_KIND_WINDOW_PARTITION: |
| 947 | + case EXPR_KIND_WINDOW_ORDER: |
| 948 | + case EXPR_KIND_WINDOW_FRAME_RANGE: |
| 949 | + case EXPR_KIND_WINDOW_FRAME_ROWS: |
| 950 | + case EXPR_KIND_WINDOW_FRAME_GROUPS: |
| 951 | + case EXPR_KIND_SELECT_TARGET: |
| 952 | + case EXPR_KIND_UPDATE_TARGET: |
| 953 | + case EXPR_KIND_UPDATE_SOURCE: |
| 954 | + case EXPR_KIND_MERGE_WHEN: |
| 955 | + case EXPR_KIND_MERGE_RETURNING: |
| 956 | + case EXPR_KIND_GROUP_BY: |
| 957 | + case EXPR_KIND_ORDER_BY: |
| 958 | + case EXPR_KIND_DISTINCT_ON: |
| 959 | + case EXPR_KIND_LIMIT: |
| 960 | + case EXPR_KIND_OFFSET: |
| 961 | + case EXPR_KIND_RETURNING: |
| 962 | + case EXPR_KIND_VALUES: |
| 963 | + case EXPR_KIND_VALUES_SINGLE: |
| 964 | + result = true; |
| 965 | + break; |
| 966 | + |
| 967 | + /* session variables not allowed */ |
| 968 | + case EXPR_KIND_INSERT_TARGET: |
| 969 | + case EXPR_KIND_EXECUTE_PARAMETER: |
| 970 | + case EXPR_KIND_CALL_ARGUMENT: |
| 971 | + case EXPR_KIND_CHECK_CONSTRAINT: |
| 972 | + case EXPR_KIND_DOMAIN_CHECK: |
| 973 | + case EXPR_KIND_COLUMN_DEFAULT: |
| 974 | + case EXPR_KIND_FUNCTION_DEFAULT: |
| 975 | + case EXPR_KIND_INDEX_EXPRESSION: |
| 976 | + case EXPR_KIND_INDEX_PREDICATE: |
| 977 | + case EXPR_KIND_STATS_EXPRESSION: |
| 978 | + case EXPR_KIND_TRIGGER_WHEN: |
| 979 | + case EXPR_KIND_PARTITION_BOUND: |
| 980 | + case EXPR_KIND_PARTITION_EXPRESSION: |
| 981 | + case EXPR_KIND_GENERATED_COLUMN: |
| 982 | + case EXPR_KIND_JOIN_USING: |
| 983 | + case EXPR_KIND_CYCLE_MARK: |
| 984 | + case EXPR_KIND_ALTER_COL_TRANSFORM: |
| 985 | + case EXPR_KIND_POLICY: |
| 986 | + case EXPR_KIND_COPY_WHERE: |
| 987 | + result = false; |
| 988 | + break; |
| 989 | + } |
| 990 | + |
| 991 | + return result; |
| 992 | +} |
| 993 | + |
| 994 | +static Node * |
| 995 | +transformVariableFence(ParseState *pstate, VariableFence *vf) |
| 996 | +{ |
| 997 | + Param *param; |
| 998 | + Oid typid; |
| 999 | + int32 typmod; |
| 1000 | + Oid collid; |
| 1001 | + |
| 1002 | + /* VariableFence can be used only in context when variables are supported */ |
| 1003 | + if (!expr_kind_allows_session_variables(pstate->p_expr_kind)) |
| 1004 | + ereport(ERROR, |
| 1005 | + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
| 1006 | + errmsg("session variable reference is not supported here"), |
| 1007 | + parser_errposition(pstate, vf->location))); |
| 1008 | + |
| 1009 | + get_session_variable_type_typmod_collid(vf->varname, |
| 1010 | + &typid, &typmod, &collid); |
| 1011 | + |
| 1012 | + |
| 1013 | + param = makeNode(Param); |
| 1014 | + |
| 1015 | + param->paramkind = PARAM_VARIABLE; |
| 1016 | + param->paramvarname = pstrdup(vf->varname); |
| 1017 | + param->paramtype = typid; |
| 1018 | + param->paramtypmod = typmod; |
| 1019 | + param->paramcollid = collid; |
| 1020 | + |
| 1021 | + pstate->p_hasSessionVariables = true; |
| 1022 | + |
| 1023 | + return (Node *) param; |
| 1024 | +} |
| 1025 | + |
907 | 1026 | /* Test whether an a_expr is a plain NULL constant or not */ |
908 | 1027 | static bool |
909 | 1028 | exprIsNullConstant(Node *arg) |
|
0 commit comments