@@ -392,6 +392,11 @@ static void get_rule_windowspec(WindowClause *wc, List *targetList,
392
392
deparse_context * context );
393
393
static char * get_variable (Var * var , int levelsup , bool istoplevel ,
394
394
deparse_context * context );
395
+ static void get_special_variable (Node * node , deparse_context * context ,
396
+ void * private );
397
+ static void resolve_special_varno (Node * node , deparse_context * context ,
398
+ void * private ,
399
+ void (* callback ) (Node * , deparse_context * , void * ));
395
400
static Node * find_param_referent (Param * param , deparse_context * context ,
396
401
deparse_namespace * * dpns_p , ListCell * * ancestor_cell_p );
397
402
static void get_parameter (Param * param , deparse_context * context );
@@ -407,7 +412,10 @@ static void get_rule_expr_toplevel(Node *node, deparse_context *context,
407
412
static void get_oper_expr (OpExpr * expr , deparse_context * context );
408
413
static void get_func_expr (FuncExpr * expr , deparse_context * context ,
409
414
bool showimplicit );
410
- static void get_agg_expr (Aggref * aggref , deparse_context * context );
415
+ static void get_agg_expr (Aggref * aggref , deparse_context * context ,
416
+ Aggref * original_aggref );
417
+ static void get_agg_combine_expr (Node * node , deparse_context * context ,
418
+ void * private );
411
419
static void get_windowfunc_expr (WindowFunc * wfunc , deparse_context * context );
412
420
static void get_coercion_expr (Node * arg , deparse_context * context ,
413
421
Oid resulttype , int32 resulttypmod ,
@@ -5877,7 +5885,6 @@ get_utility_query_def(Query *query, deparse_context *context)
5877
5885
}
5878
5886
}
5879
5887
5880
-
5881
5888
/*
5882
5889
* Display a Var appropriately.
5883
5890
*
@@ -5930,82 +5937,11 @@ get_variable(Var *var, int levelsup, bool istoplevel, deparse_context *context)
5930
5937
colinfo = deparse_columns_fetch (var -> varno , dpns );
5931
5938
attnum = var -> varattno ;
5932
5939
}
5933
- else if (var -> varno == OUTER_VAR && dpns -> outer_tlist )
5934
- {
5935
- TargetEntry * tle ;
5936
- deparse_namespace save_dpns ;
5937
-
5938
- tle = get_tle_by_resno (dpns -> outer_tlist , var -> varattno );
5939
- if (!tle )
5940
- elog (ERROR , "bogus varattno for OUTER_VAR var: %d" , var -> varattno );
5941
-
5942
- Assert (netlevelsup == 0 );
5943
- push_child_plan (dpns , dpns -> outer_planstate , & save_dpns );
5944
-
5945
- /*
5946
- * Force parentheses because our caller probably assumed a Var is a
5947
- * simple expression.
5948
- */
5949
- if (!IsA (tle -> expr , Var ))
5950
- appendStringInfoChar (buf , '(' );
5951
- get_rule_expr ((Node * ) tle -> expr , context , true);
5952
- if (!IsA (tle -> expr , Var ))
5953
- appendStringInfoChar (buf , ')' );
5954
-
5955
- pop_child_plan (dpns , & save_dpns );
5956
- return NULL ;
5957
- }
5958
- else if (var -> varno == INNER_VAR && dpns -> inner_tlist )
5959
- {
5960
- TargetEntry * tle ;
5961
- deparse_namespace save_dpns ;
5962
-
5963
- tle = get_tle_by_resno (dpns -> inner_tlist , var -> varattno );
5964
- if (!tle )
5965
- elog (ERROR , "bogus varattno for INNER_VAR var: %d" , var -> varattno );
5966
-
5967
- Assert (netlevelsup == 0 );
5968
- push_child_plan (dpns , dpns -> inner_planstate , & save_dpns );
5969
-
5970
- /*
5971
- * Force parentheses because our caller probably assumed a Var is a
5972
- * simple expression.
5973
- */
5974
- if (!IsA (tle -> expr , Var ))
5975
- appendStringInfoChar (buf , '(' );
5976
- get_rule_expr ((Node * ) tle -> expr , context , true);
5977
- if (!IsA (tle -> expr , Var ))
5978
- appendStringInfoChar (buf , ')' );
5979
-
5980
- pop_child_plan (dpns , & save_dpns );
5981
- return NULL ;
5982
- }
5983
- else if (var -> varno == INDEX_VAR && dpns -> index_tlist )
5984
- {
5985
- TargetEntry * tle ;
5986
-
5987
- tle = get_tle_by_resno (dpns -> index_tlist , var -> varattno );
5988
- if (!tle )
5989
- elog (ERROR , "bogus varattno for INDEX_VAR var: %d" , var -> varattno );
5990
-
5991
- Assert (netlevelsup == 0 );
5992
-
5993
- /*
5994
- * Force parentheses because our caller probably assumed a Var is a
5995
- * simple expression.
5996
- */
5997
- if (!IsA (tle -> expr , Var ))
5998
- appendStringInfoChar (buf , '(' );
5999
- get_rule_expr ((Node * ) tle -> expr , context , true);
6000
- if (!IsA (tle -> expr , Var ))
6001
- appendStringInfoChar (buf , ')' );
6002
-
6003
- return NULL ;
6004
- }
6005
5940
else
6006
5941
{
6007
- elog (ERROR , "bogus varno: %d" , var -> varno );
6008
- return NULL ; /* keep compiler quiet */
5942
+ resolve_special_varno ((Node * ) var , context , NULL ,
5943
+ get_special_variable );
5944
+ return NULL ;
6009
5945
}
6010
5946
6011
5947
/*
@@ -6118,6 +6054,101 @@ get_variable(Var *var, int levelsup, bool istoplevel, deparse_context *context)
6118
6054
return attname ;
6119
6055
}
6120
6056
6057
+ /*
6058
+ * Deparse a Var which references OUTER_VAR, INNER_VAR, or INDEX_VAR. This
6059
+ * routine is actually a callback for get_special_varno, which handles finding
6060
+ * the correct TargetEntry. We get the expression contained in that
6061
+ * TargetEntry and just need to deparse it, a job we can throw back on
6062
+ * get_rule_expr.
6063
+ */
6064
+ static void
6065
+ get_special_variable (Node * node , deparse_context * context , void * private )
6066
+ {
6067
+ StringInfo buf = context -> buf ;
6068
+
6069
+ /*
6070
+ * Force parentheses because our caller probably assumed a Var is a simple
6071
+ * expression.
6072
+ */
6073
+ if (!IsA (node , Var ))
6074
+ appendStringInfoChar (buf , '(' );
6075
+ get_rule_expr (node , context , true);
6076
+ if (!IsA (node , Var ))
6077
+ appendStringInfoChar (buf , ')' );
6078
+ }
6079
+
6080
+ /*
6081
+ * Chase through plan references to special varnos (OUTER_VAR, INNER_VAR,
6082
+ * INDEX_VAR) until we find a real Var or some kind of non-Var node; then,
6083
+ * invoke the callback provided.
6084
+ */
6085
+ static void
6086
+ resolve_special_varno (Node * node , deparse_context * context , void * private ,
6087
+ void (* callback ) (Node * , deparse_context * , void * ))
6088
+ {
6089
+ Var * var ;
6090
+ deparse_namespace * dpns ;
6091
+
6092
+ /* If it's not a Var, invoke the callback. */
6093
+ if (!IsA (node , Var ))
6094
+ {
6095
+ callback (node , context , private );
6096
+ return ;
6097
+ }
6098
+
6099
+ /* Find appropriate nesting depth */
6100
+ var = (Var * ) node ;
6101
+ dpns = (deparse_namespace * ) list_nth (context -> namespaces ,
6102
+ var -> varlevelsup );
6103
+
6104
+ /*
6105
+ * It's a special RTE, so recurse.
6106
+ */
6107
+ if (var -> varno == OUTER_VAR && dpns -> outer_tlist )
6108
+ {
6109
+ TargetEntry * tle ;
6110
+ deparse_namespace save_dpns ;
6111
+
6112
+ tle = get_tle_by_resno (dpns -> outer_tlist , var -> varattno );
6113
+ if (!tle )
6114
+ elog (ERROR , "bogus varattno for OUTER_VAR var: %d" , var -> varattno );
6115
+
6116
+ push_child_plan (dpns , dpns -> outer_planstate , & save_dpns );
6117
+ resolve_special_varno ((Node * ) tle -> expr , context , private , callback );
6118
+ pop_child_plan (dpns , & save_dpns );
6119
+ return ;
6120
+ }
6121
+ else if (var -> varno == INNER_VAR && dpns -> inner_tlist )
6122
+ {
6123
+ TargetEntry * tle ;
6124
+ deparse_namespace save_dpns ;
6125
+
6126
+ tle = get_tle_by_resno (dpns -> inner_tlist , var -> varattno );
6127
+ if (!tle )
6128
+ elog (ERROR , "bogus varattno for INNER_VAR var: %d" , var -> varattno );
6129
+
6130
+ push_child_plan (dpns , dpns -> inner_planstate , & save_dpns );
6131
+ resolve_special_varno ((Node * ) tle -> expr , context , private , callback );
6132
+ pop_child_plan (dpns , & save_dpns );
6133
+ return ;
6134
+ }
6135
+ else if (var -> varno == INDEX_VAR && dpns -> index_tlist )
6136
+ {
6137
+ TargetEntry * tle ;
6138
+
6139
+ tle = get_tle_by_resno (dpns -> index_tlist , var -> varattno );
6140
+ if (!tle )
6141
+ elog (ERROR , "bogus varattno for INDEX_VAR var: %d" , var -> varattno );
6142
+
6143
+ resolve_special_varno ((Node * ) tle -> expr , context , private , callback );
6144
+ return ;
6145
+ }
6146
+ else if (var -> varno < 1 || var -> varno > list_length (dpns -> rtable ))
6147
+ elog (ERROR , "bogus varno: %d" , var -> varno );
6148
+
6149
+ /* Not special. Just invoke the callback. */
6150
+ callback (node , context , private );
6151
+ }
6121
6152
6122
6153
/*
6123
6154
* Get the name of a field of an expression of composite type. The
@@ -7080,7 +7111,7 @@ get_rule_expr(Node *node, deparse_context *context,
7080
7111
break ;
7081
7112
7082
7113
case T_Aggref :
7083
- get_agg_expr ((Aggref * ) node , context );
7114
+ get_agg_expr ((Aggref * ) node , context , ( Aggref * ) node );
7084
7115
break ;
7085
7116
7086
7117
case T_GroupingFunc :
@@ -8236,13 +8267,36 @@ get_func_expr(FuncExpr *expr, deparse_context *context,
8236
8267
* get_agg_expr - Parse back an Aggref node
8237
8268
*/
8238
8269
static void
8239
- get_agg_expr (Aggref * aggref , deparse_context * context )
8270
+ get_agg_expr (Aggref * aggref , deparse_context * context ,
8271
+ Aggref * original_aggref )
8240
8272
{
8241
8273
StringInfo buf = context -> buf ;
8242
8274
Oid argtypes [FUNC_MAX_ARGS ];
8243
8275
int nargs ;
8244
8276
bool use_variadic ;
8245
8277
8278
+ /*
8279
+ * For a combining aggregate, we look up and deparse the corresponding
8280
+ * partial aggregate instead. This is necessary because our input
8281
+ * argument list has been replaced; the new argument list always has just
8282
+ * one element, which will point to a partial Aggref that supplies us with
8283
+ * transition states to combine.
8284
+ */
8285
+ if (aggref -> aggcombine )
8286
+ {
8287
+ TargetEntry * tle = linitial (aggref -> args );
8288
+
8289
+ Assert (list_length (aggref -> args ) == 1 );
8290
+ Assert (IsA (tle , TargetEntry ));
8291
+ resolve_special_varno ((Node * ) tle -> expr , context , original_aggref ,
8292
+ get_agg_combine_expr );
8293
+ return ;
8294
+ }
8295
+
8296
+ /* Mark as PARTIAL, if appropriate. */
8297
+ if (original_aggref -> aggpartial )
8298
+ appendStringInfoString (buf , "PARTIAL " );
8299
+
8246
8300
/* Extract the argument types as seen by the parser */
8247
8301
nargs = get_aggregate_argtypes (aggref , argtypes );
8248
8302
@@ -8311,6 +8365,24 @@ get_agg_expr(Aggref *aggref, deparse_context *context)
8311
8365
appendStringInfoChar (buf , ')' );
8312
8366
}
8313
8367
8368
+ /*
8369
+ * This is a helper function for get_agg_expr(). It's used when we deparse
8370
+ * a combining Aggref; resolve_special_varno locates the corresponding partial
8371
+ * Aggref and then calls this.
8372
+ */
8373
+ static void
8374
+ get_agg_combine_expr (Node * node , deparse_context * context , void * private )
8375
+ {
8376
+ Aggref * aggref ;
8377
+ Aggref * original_aggref = private ;
8378
+
8379
+ if (!IsA (node , Aggref ))
8380
+ elog (ERROR , "combining Aggref does not point to an Aggref" );
8381
+
8382
+ aggref = (Aggref * ) node ;
8383
+ get_agg_expr (aggref , context , original_aggref );
8384
+ }
8385
+
8314
8386
/*
8315
8387
* get_windowfunc_expr - Parse back a WindowFunc node
8316
8388
*/
0 commit comments