5555#include "utils/syscache.h"
5656
5757
58+ /* Passthrough data for transformPLAssignStmtTarget */
59+ typedef struct SelectStmtPassthrough
60+ {
61+ PLAssignStmt * stmt ; /* the assignment statement */
62+ Node * target ; /* node representing the target variable */
63+ List * indirection ; /* indirection yet to be applied to target */
64+ } SelectStmtPassthrough ;
65+
5866/* Hook for plugins to get control at end of parse analysis */
5967post_parse_analyze_hook_type post_parse_analyze_hook = NULL ;
6068
@@ -64,7 +72,8 @@ static Query *transformInsertStmt(ParseState *pstate, InsertStmt *stmt);
6472static OnConflictExpr * transformOnConflictClause (ParseState * pstate ,
6573 OnConflictClause * onConflictClause );
6674static int count_rowexpr_columns (ParseState * pstate , Node * expr );
67- static Query * transformSelectStmt (ParseState * pstate , SelectStmt * stmt );
75+ static Query * transformSelectStmt (ParseState * pstate , SelectStmt * stmt ,
76+ SelectStmtPassthrough * passthru );
6877static Query * transformValuesClause (ParseState * pstate , SelectStmt * stmt );
6978static Query * transformSetOperationStmt (ParseState * pstate , SelectStmt * stmt );
7079static Node * transformSetOperationTree (ParseState * pstate , SelectStmt * stmt ,
@@ -75,6 +84,8 @@ static Query *transformReturnStmt(ParseState *pstate, ReturnStmt *stmt);
7584static Query * transformUpdateStmt (ParseState * pstate , UpdateStmt * stmt );
7685static Query * transformPLAssignStmt (ParseState * pstate ,
7786 PLAssignStmt * stmt );
87+ static List * transformPLAssignStmtTarget (ParseState * pstate , List * tlist ,
88+ SelectStmtPassthrough * passthru );
7889static Query * transformDeclareCursorStmt (ParseState * pstate ,
7990 DeclareCursorStmt * stmt );
8091static Query * transformExplainStmt (ParseState * pstate ,
@@ -371,7 +382,7 @@ transformStmt(ParseState *pstate, Node *parseTree)
371382 if (n -> valuesLists )
372383 result = transformValuesClause (pstate , n );
373384 else if (n -> op == SETOP_NONE )
374- result = transformSelectStmt (pstate , n );
385+ result = transformSelectStmt (pstate , n , NULL );
375386 else
376387 result = transformSetOperationStmt (pstate , n );
377388 }
@@ -1374,11 +1385,19 @@ count_rowexpr_columns(ParseState *pstate, Node *expr)
13741385 * transformSelectStmt -
13751386 * transforms a Select Statement
13761387 *
1388+ * This function is also used to transform the source expression of a
1389+ * PLAssignStmt. In that usage, passthru is non-NULL and we need to
1390+ * call transformPLAssignStmtTarget after the initial transformation of the
1391+ * SELECT's targetlist. (We could generalize this into an arbitrary callback
1392+ * function, but for now that would just be more notation with no benefit.)
1393+ * All the rest is the same as a regular SelectStmt.
1394+ *
13771395 * Note: this covers only cases with no set operations and no VALUES lists;
13781396 * see below for the other cases.
13791397 */
13801398static Query *
1381- transformSelectStmt (ParseState * pstate , SelectStmt * stmt )
1399+ transformSelectStmt (ParseState * pstate , SelectStmt * stmt ,
1400+ SelectStmtPassthrough * passthru )
13821401{
13831402 Query * qry = makeNode (Query );
13841403 Node * qual ;
@@ -1415,8 +1434,16 @@ transformSelectStmt(ParseState *pstate, SelectStmt *stmt)
14151434 qry -> targetList = transformTargetList (pstate , stmt -> targetList ,
14161435 EXPR_KIND_SELECT_TARGET );
14171436
1418- /* mark column origins */
1419- markTargetListOrigins (pstate , qry -> targetList );
1437+ /*
1438+ * If we're within a PLAssignStmt, do further transformation of the
1439+ * targetlist; that has to happen before we consider sorting or grouping.
1440+ * Otherwise, mark column origins (which are useless in a PLAssignStmt).
1441+ */
1442+ if (passthru )
1443+ qry -> targetList = transformPLAssignStmtTarget (pstate , qry -> targetList ,
1444+ passthru );
1445+ else
1446+ markTargetListOrigins (pstate , qry -> targetList );
14201447
14211448 /* transform WHERE */
14221449 qual = transformWhereClause (pstate , stmt -> whereClause ,
@@ -2763,20 +2790,13 @@ transformReturningClause(ParseState *pstate, Query *qry,
27632790static Query *
27642791transformPLAssignStmt (ParseState * pstate , PLAssignStmt * stmt )
27652792{
2766- Query * qry = makeNode ( Query ) ;
2793+ Query * qry ;
27672794 ColumnRef * cref = makeNode (ColumnRef );
27682795 List * indirection = stmt -> indirection ;
27692796 int nnames = stmt -> nnames ;
2770- SelectStmt * sstmt = stmt -> val ;
27712797 Node * target ;
2772- Oid targettype ;
2773- int32 targettypmod ;
2774- Oid targetcollation ;
2775- List * tlist ;
2776- TargetEntry * tle ;
2777- Oid type_id ;
2778- Node * qual ;
2779- ListCell * l ;
2798+ SelectStmtPassthrough passthru ;
2799+ bool save_resolve_unknowns ;
27802800
27812801 /*
27822802 * First, construct a ColumnRef for the target variable. If the target
@@ -2802,33 +2822,62 @@ transformPLAssignStmt(ParseState *pstate, PLAssignStmt *stmt)
28022822
28032823 /*
28042824 * Transform the target reference. Typically we will get back a Param
2805- * node, but there's no reason to be too picky about its type.
2825+ * node, but there's no reason to be too picky about its type. (Note that
2826+ * we must do this before calling transformSelectStmt. It's tempting to
2827+ * do it inside transformPLAssignStmtTarget, but we need to do it before
2828+ * adding any FROM tables to the pstate's namespace, else we might wrongly
2829+ * resolve the target as a table column.)
28062830 */
28072831 target = transformExpr (pstate , (Node * ) cref ,
28082832 EXPR_KIND_UPDATE_TARGET );
2809- targettype = exprType (target );
2810- targettypmod = exprTypmod (target );
2811- targetcollation = exprCollation (target );
2833+
2834+ /* Set up passthrough data for transformPLAssignStmtTarget */
2835+ passthru .stmt = stmt ;
2836+ passthru .target = target ;
2837+ passthru .indirection = indirection ;
28122838
28132839 /*
2814- * The rest mostly matches transformSelectStmt, except that we needn't
2815- * consider WITH or INTO, and we build a targetlist our own way.
2840+ * To avoid duplicating a lot of code, we use transformSelectStmt to do
2841+ * almost all of the work. However, we need to do additional processing
2842+ * on the SELECT's targetlist after it's been transformed, but before
2843+ * possible addition of targetlist items for ORDER BY or GROUP BY.
2844+ * transformSelectStmt knows it should call transformPLAssignStmtTarget if
2845+ * it's passed a passthru argument.
2846+ *
2847+ * Also, disable resolution of unknown-type tlist items; PL/pgSQL wants to
2848+ * deal with that itself.
28162849 */
2817- qry -> commandType = CMD_SELECT ;
2818- pstate -> p_is_insert = false;
2850+ save_resolve_unknowns = pstate -> p_resolve_unknowns ;
2851+ pstate -> p_resolve_unknowns = false;
2852+ qry = transformSelectStmt (pstate , stmt -> val , & passthru );
2853+ pstate -> p_resolve_unknowns = save_resolve_unknowns ;
28192854
2820- /* make FOR UPDATE/FOR SHARE info available to addRangeTableEntry */
2821- pstate -> p_locking_clause = sstmt -> lockingClause ;
2822-
2823- /* make WINDOW info available for window functions, too */
2824- pstate -> p_windowdefs = sstmt -> windowClause ;
2855+ return qry ;
2856+ }
28252857
2826- /* process the FROM clause */
2827- transformFromClause (pstate , sstmt -> fromClause );
2858+ /*
2859+ * Callback function to adjust a SELECT's tlist to make the output suitable
2860+ * for assignment to a PLAssignStmt's target variable.
2861+ *
2862+ * Note: we actually modify the tle->expr in-place, but the function's API
2863+ * is set up to not presume that.
2864+ */
2865+ static List *
2866+ transformPLAssignStmtTarget (ParseState * pstate , List * tlist ,
2867+ SelectStmtPassthrough * passthru )
2868+ {
2869+ PLAssignStmt * stmt = passthru -> stmt ;
2870+ Node * target = passthru -> target ;
2871+ List * indirection = passthru -> indirection ;
2872+ Oid targettype ;
2873+ int32 targettypmod ;
2874+ Oid targetcollation ;
2875+ TargetEntry * tle ;
2876+ Oid type_id ;
28282877
2829- /* initially transform the targetlist as if in SELECT */
2830- tlist = transformTargetList ( pstate , sstmt -> targetList ,
2831- EXPR_KIND_SELECT_TARGET );
2878+ targettype = exprType ( target );
2879+ targettypmod = exprTypmod ( target );
2880+ targetcollation = exprCollation ( target );
28322881
28332882 /* we should have exactly one targetlist item */
28342883 if (list_length (tlist ) != 1 )
@@ -2906,97 +2955,7 @@ transformPLAssignStmt(ParseState *pstate, PLAssignStmt *stmt)
29062955
29072956 pstate -> p_expr_kind = EXPR_KIND_NONE ;
29082957
2909- qry -> targetList = list_make1 (tle );
2910-
2911- /* transform WHERE */
2912- qual = transformWhereClause (pstate , sstmt -> whereClause ,
2913- EXPR_KIND_WHERE , "WHERE" );
2914-
2915- /* initial processing of HAVING clause is much like WHERE clause */
2916- qry -> havingQual = transformWhereClause (pstate , sstmt -> havingClause ,
2917- EXPR_KIND_HAVING , "HAVING" );
2918-
2919- /*
2920- * Transform sorting/grouping stuff. Do ORDER BY first because both
2921- * transformGroupClause and transformDistinctClause need the results. Note
2922- * that these functions can also change the targetList, so it's passed to
2923- * them by reference.
2924- */
2925- qry -> sortClause = transformSortClause (pstate ,
2926- sstmt -> sortClause ,
2927- & qry -> targetList ,
2928- EXPR_KIND_ORDER_BY ,
2929- false /* allow SQL92 rules */ );
2930-
2931- qry -> groupClause = transformGroupClause (pstate ,
2932- sstmt -> groupClause ,
2933- & qry -> groupingSets ,
2934- & qry -> targetList ,
2935- qry -> sortClause ,
2936- EXPR_KIND_GROUP_BY ,
2937- false /* allow SQL92 rules */ );
2938- qry -> groupDistinct = sstmt -> groupDistinct ;
2939-
2940- if (sstmt -> distinctClause == NIL )
2941- {
2942- qry -> distinctClause = NIL ;
2943- qry -> hasDistinctOn = false;
2944- }
2945- else if (linitial (sstmt -> distinctClause ) == NULL )
2946- {
2947- /* We had SELECT DISTINCT */
2948- qry -> distinctClause = transformDistinctClause (pstate ,
2949- & qry -> targetList ,
2950- qry -> sortClause ,
2951- false);
2952- qry -> hasDistinctOn = false;
2953- }
2954- else
2955- {
2956- /* We had SELECT DISTINCT ON */
2957- qry -> distinctClause = transformDistinctOnClause (pstate ,
2958- sstmt -> distinctClause ,
2959- & qry -> targetList ,
2960- qry -> sortClause );
2961- qry -> hasDistinctOn = true;
2962- }
2963-
2964- /* transform LIMIT */
2965- qry -> limitOffset = transformLimitClause (pstate , sstmt -> limitOffset ,
2966- EXPR_KIND_OFFSET , "OFFSET" ,
2967- sstmt -> limitOption );
2968- qry -> limitCount = transformLimitClause (pstate , sstmt -> limitCount ,
2969- EXPR_KIND_LIMIT , "LIMIT" ,
2970- sstmt -> limitOption );
2971- qry -> limitOption = sstmt -> limitOption ;
2972-
2973- /* transform window clauses after we have seen all window functions */
2974- qry -> windowClause = transformWindowDefinitions (pstate ,
2975- pstate -> p_windowdefs ,
2976- & qry -> targetList );
2977-
2978- qry -> rtable = pstate -> p_rtable ;
2979- qry -> rteperminfos = pstate -> p_rteperminfos ;
2980- qry -> jointree = makeFromExpr (pstate -> p_joinlist , qual );
2981-
2982- qry -> hasSubLinks = pstate -> p_hasSubLinks ;
2983- qry -> hasWindowFuncs = pstate -> p_hasWindowFuncs ;
2984- qry -> hasTargetSRFs = pstate -> p_hasTargetSRFs ;
2985- qry -> hasAggs = pstate -> p_hasAggs ;
2986-
2987- foreach (l , sstmt -> lockingClause )
2988- {
2989- transformLockingClause (pstate , qry ,
2990- (LockingClause * ) lfirst (l ), false);
2991- }
2992-
2993- assign_query_collations (pstate , qry );
2994-
2995- /* this must be done after collations, for reliable comparison of exprs */
2996- if (pstate -> p_hasAggs || qry -> groupClause || qry -> groupingSets || qry -> havingQual )
2997- parseCheckAggregates (pstate , qry );
2998-
2999- return qry ;
2958+ return list_make1 (tle );
30002959}
30012960
30022961
0 commit comments