11/*-------------------------------------------------------------------------
22 *
3- * ruleutils .c
3+ * pg_ruleutils_19 .c
44 * Functions to convert stored expressions/querytrees back to
55 * source text
66 *
77 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
88 * Portions Copyright (c) 1994, Regents of the University of California
99 *
10- *
11- * IDENTIFICATION
12- * src/backend/utils/adt/ruleutils.c
13- *
1410 *-------------------------------------------------------------------------
1511 */
1612#include "postgres.h"
1713
14+ #if PG_VERSION_NUM >= 190000 && PG_VERSION_NUM < 200000
15+
16+ #pragma GCC diagnostic ignored "-Wshadow" // ignore any compiler warnings
17+ #pragma GCC diagnostic ignored "-Wsign-compare" // ignore any compiler warnings
18+ #pragma GCC diagnostic ignored "-Wunused-parameter" // ignore any compiler warnings
19+
1820#include <ctype.h>
1921#include <unistd.h>
2022#include <fcntl.h>
6567#include "utils/lsyscache.h"
6668#include "utils/partcache.h"
6769#include "utils/rel.h"
68- #include "utils/ruleutils .h"
70+ #include "pgduckdb/vendor/pg_ruleutils .h"
6971#include "utils/snapmgr.h"
7072#include "utils/syscache.h"
7173#include "utils/typcache.h"
7274#include "utils/varlena.h"
7375#include "utils/xml.h"
7476
77+ #include "pgduckdb/pgduckdb_ruleutils.h"
78+
79+ #include "pgduckdb/utility/rename_ruleutils.h"
80+
7581/* ----------
7682 * Pretty formatting constants
7783 * ----------
9298/* Standard conversion of a "bool pretty" option to detailed flags */
9399#define GET_PRETTY_FLAGS (pretty ) \
94100 ((pretty) ? (PRETTYFLAG_PAREN | PRETTYFLAG_INDENT | PRETTYFLAG_SCHEMA) \
95- : PRETTYFLAG_INDENT )
101+ : 0 )
96102
97103/* Default line length for pretty-print wrapping: 0 means wrap always */
98104#define WRAP_COLUMN_DEFAULT 0
@@ -525,8 +531,6 @@ static void get_opclass_name(Oid opclass, Oid actual_datatype,
525531static Node * processIndirection (Node * node , deparse_context * context );
526532static void printSubscripts (SubscriptingRef * sbsref , deparse_context * context );
527533static char * get_relation_name (Oid relid );
528- static char * generate_relation_name (Oid relid , List * namespaces );
529- static char * generate_qualified_relation_name (Oid relid );
530534static char * generate_function_name (Oid funcid , int nargs ,
531535 List * argnames , Oid * argtypes ,
532536 bool has_variadic , bool * use_variadic_p ,
@@ -5776,6 +5780,9 @@ get_with_clause(Query *query, deparse_context *context)
57765780 if (query -> cteList == NIL )
57775781 return ;
57785782
5783+ bool previous_outermost_query = outermost_query ;
5784+ outermost_query = false;
5785+
57795786 if (PRETTY_INDENT (context ))
57805787 {
57815788 context -> indentLevel += PRETTYINDENT_STD ;
@@ -5899,6 +5906,8 @@ get_with_clause(Query *query, deparse_context *context)
58995906 }
59005907 else
59015908 appendStringInfoChar (buf , ' ' );
5909+
5910+ outermost_query = previous_outermost_query ;
59025911}
59035912
59045913/* ----------
@@ -6255,12 +6264,23 @@ get_target_list(List *targetList, deparse_context *context)
62556264
62566265 sep = " " ;
62576266 colno = 0 ;
6267+
6268+ StarReconstructionContext star_reconstruction_context = {0 };
6269+ star_reconstruction_context .target_list = targetList ;
6270+
6271+ bool outermost_targetlist = outermost_query ;
6272+ outermost_query = false;
6273+
62586274 foreach (l , targetList )
62596275 {
62606276 TargetEntry * tle = (TargetEntry * ) lfirst (l );
62616277 char * colname ;
62626278 char * attname ;
62636279
6280+ if (pgduckdb_reconstruct_star_step (& star_reconstruction_context , l )) {
6281+ continue ;
6282+ }
6283+
62646284 if (tle -> resjunk )
62656285 continue ; /* ignore junk entries */
62666286
@@ -6285,8 +6305,10 @@ get_target_list(List *targetList, deparse_context *context)
62856305 * directly so that we can tell it to do the right thing, and so that
62866306 * we can get the attribute name which is the default AS label.
62876307 */
6308+ Var * var = NULL ;
62886309 if (tle -> expr && (IsA (tle -> expr , Var )))
62896310 {
6311+ var = (Var * ) tle -> expr ;
62906312 attname = get_variable ((Var * ) tle -> expr , 0 , true, context );
62916313 }
62926314 else
@@ -6313,8 +6335,33 @@ get_target_list(List *targetList, deparse_context *context)
63136335 else
63146336 colname = tle -> resname ;
63156337
6338+ /*
6339+ * This makes sure we don't add Postgres its bad default alias to the
6340+ * duckdb.row type.
6341+ */
6342+ bool duckdb_skip_as = pgduckdb_var_is_duckdb_row (var );
6343+
6344+ /*
6345+ * For r['abc'] expressions we don't want the column name to be r, but
6346+ * instead we want it to be "abc". We can only to do this for the
6347+ * target list of the outside most query though to make sure references
6348+ * to the column name are still valid.
6349+ */
6350+ if (!duckdb_skip_as && outermost_targetlist ) {
6351+ Var * subscript_var = pgduckdb_duckdb_subscript_var (tle -> expr );
6352+ if (subscript_var ) {
6353+ /*
6354+ * This cannot be moved to pgduckdb_ruleutils, because of
6355+ * the reliance on the non-public deparse_namespace type.
6356+ */
6357+ deparse_namespace * dpns = (deparse_namespace * ) list_nth (context -> namespaces ,
6358+ subscript_var -> varlevelsup );
6359+ duckdb_skip_as = !pgduckdb_subscript_has_custom_alias (dpns -> plan , dpns -> rtable , subscript_var , colname );
6360+ }
6361+ }
6362+
63166363 /* Show AS unless the column's name is correct as-is */
6317- if (colname ) /* resname could be NULL */
6364+ if (colname && ! duckdb_skip_as ) /* resname could be NULL */
63186365 {
63196366 if (attname == NULL || strcmp (attname , colname ) != 0 )
63206367 appendStringInfo (& targetbuf , " AS %s" , quote_identifier (colname ));
@@ -7014,6 +7061,16 @@ get_insert_query_def(Query *query, deparse_context *context)
70147061 if (tle -> resjunk )
70157062 continue ; /* ignore junk entries */
70167063
7064+ /*
7065+ * If it's an INSERT ... SELECT or multi-row VALUES, the entry
7066+ * with the default value is ignored unless it is specified
7067+ */
7068+ if (values_rte || select_rte )
7069+ {
7070+ if (!pgduckdb_is_not_default_expr ((Node * ) tle , NULL ))
7071+ continue ;
7072+ }
7073+
70177074 appendStringInfoString (buf , sep );
70187075 sep = ", " ;
70197076
@@ -7806,6 +7863,11 @@ get_variable(Var *var, int levelsup, bool istoplevel, deparse_context *context)
78067863 if (attnum > colinfo -> num_cols )
78077864 elog (ERROR , "invalid attnum %d for relation \"%s\"" ,
78087865 attnum , rte -> eref -> aliasname );
7866+
7867+ if (pgduckdb_var_is_duckdb_row (var )) {
7868+ return pgduckdb_write_row_refname (context -> buf , refname , istoplevel );
7869+ }
7870+
78097871 attname = colinfo -> colnames [attnum - 1 ];
78107872
78117873 /*
@@ -9377,8 +9439,9 @@ get_rule_expr(Node *node, deparse_context *context,
93779439 }
93789440 else
93799441 {
9442+ SubscriptingRef * new_sbsref = pgduckdb_strip_first_subscript (sbsref , context -> buf );
93809443 /* Just an ordinary container fetch, so print subscripts */
9381- printSubscripts (sbsref , context );
9444+ printSubscripts (new_sbsref , context );
93829445 }
93839446 }
93849447 break ;
@@ -10774,12 +10837,13 @@ get_oper_expr(OpExpr *expr, deparse_context *context)
1077410837 Node * arg1 = (Node * ) linitial (args );
1077510838 Node * arg2 = (Node * ) lsecond (args );
1077610839
10840+ char * op_name = generate_operator_name (opno , exprType (arg1 ), exprType (arg2 ));
10841+ void * ctx = pg_duckdb_get_oper_expr_make_ctx (op_name , & arg1 , & arg2 );
10842+ pg_duckdb_get_oper_expr_prefix (buf , ctx );
1077710843 get_rule_expr_paren (arg1 , context , true, (Node * ) expr );
10778- appendStringInfo (buf , " %s " ,
10779- generate_operator_name (opno ,
10780- exprType (arg1 ),
10781- exprType (arg2 )));
10844+ pg_duckdb_get_oper_expr_middle (buf , ctx );
1078210845 get_rule_expr_paren (arg2 , context , true, (Node * ) expr );
10846+ pg_duckdb_get_oper_expr_suffix (buf , ctx );
1078310847 }
1078410848 else
1078510849 {
@@ -11468,6 +11532,10 @@ get_coercion_expr(Node *arg, deparse_context *context,
1146811532 appendStringInfoChar (buf , ')' );
1146911533 }
1147011534
11535+ if (pgduckdb_is_fake_type (resulttype )) {
11536+ return ;
11537+ }
11538+
1147111539 /*
1147211540 * Never emit resulttype(arg) functional notation. A pg_proc entry could
1147311541 * take precedence, and a resulttype in pg_temp would require schema
@@ -11503,6 +11571,8 @@ get_const_expr(Const *constval, deparse_context *context, int showtype)
1150311571 char * extval ;
1150411572 bool needlabel = false;
1150511573
11574+ showtype = pgduckdb_show_type (constval , showtype );
11575+
1150611576 if (constval -> constisnull )
1150711577 {
1150811578 /*
@@ -12421,6 +12491,9 @@ get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
1242112491 break ;
1242212492 case RTE_SUBQUERY :
1242312493 /* Subquery RTE */
12494+ if (pgduckdb_replace_subquery_with_view (rte -> subquery , buf )) {
12495+ break ;
12496+ }
1242412497 appendStringInfoChar (buf , '(' );
1242512498 get_query_def (rte -> subquery , buf , context -> namespaces , NULL ,
1242612499 true,
@@ -12543,8 +12616,18 @@ get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
1254312616 /* Print the relation alias, if needed */
1254412617 get_rte_alias (rte , varno , false, context );
1254512618
12619+ if (pgduckdb_func_returns_duckdb_row (rtfunc1 )) {
12620+ /*
12621+ * We never want to print column aliases for functions that return
12622+ * a duckdb.row. The common pattern is for people to not provide an
12623+ * explicit column alias (i.e. "r" becomes "r(r)"). This obviously
12624+ * is a naming collision and DuckDB resolves that in the opposite
12625+ * way that we want. Never adding column aliases for duckdb.row
12626+ * avoids this conflict.
12627+ */
12628+ }
1254612629 /* Print the column definitions or aliases, if needed */
12547- if (rtfunc1 && rtfunc1 -> funccolnames != NIL )
12630+ else if (rtfunc1 && rtfunc1 -> funccolnames != NIL )
1254812631 {
1254912632 /* Reconstruct the columndef list, which is also the aliases */
1255012633 get_from_clause_coldeflist (rtfunc1 , colinfo , context );
@@ -12870,6 +12953,10 @@ get_tablesample_def(TableSampleClause *tablesample, deparse_context *context)
1287012953 if (nargs ++ > 0 )
1287112954 appendStringInfoString (buf , ", " );
1287212955 get_rule_expr ((Node * ) lfirst (l ), context , false);
12956+ const char * tsm_name = generate_function_name (tablesample -> tsmhandler , 1 ,
12957+ NIL , argtypes ,
12958+ false, NULL , EXPR_KIND_NONE );
12959+ pgduckdb_add_tablesample_percent (tsm_name , buf , list_length (tablesample -> args ));
1287312960 }
1287412961 appendStringInfoChar (buf , ')' );
1287512962
@@ -13172,102 +13259,6 @@ get_relation_name(Oid relid)
1317213259 return relname ;
1317313260}
1317413261
13175- /*
13176- * generate_relation_name
13177- * Compute the name to display for a relation specified by OID
13178- *
13179- * The result includes all necessary quoting and schema-prefixing.
13180- *
13181- * If namespaces isn't NIL, it must be a list of deparse_namespace nodes.
13182- * We will forcibly qualify the relation name if it equals any CTE name
13183- * visible in the namespace list.
13184- */
13185- static char *
13186- generate_relation_name (Oid relid , List * namespaces )
13187- {
13188- HeapTuple tp ;
13189- Form_pg_class reltup ;
13190- bool need_qual ;
13191- ListCell * nslist ;
13192- char * relname ;
13193- char * nspname ;
13194- char * result ;
13195-
13196- tp = SearchSysCache1 (RELOID , ObjectIdGetDatum (relid ));
13197- if (!HeapTupleIsValid (tp ))
13198- elog (ERROR , "cache lookup failed for relation %u" , relid );
13199- reltup = (Form_pg_class ) GETSTRUCT (tp );
13200- relname = NameStr (reltup -> relname );
13201-
13202- /* Check for conflicting CTE name */
13203- need_qual = false;
13204- foreach (nslist , namespaces )
13205- {
13206- deparse_namespace * dpns = (deparse_namespace * ) lfirst (nslist );
13207- ListCell * ctlist ;
13208-
13209- foreach (ctlist , dpns -> ctes )
13210- {
13211- CommonTableExpr * cte = (CommonTableExpr * ) lfirst (ctlist );
13212-
13213- if (strcmp (cte -> ctename , relname ) == 0 )
13214- {
13215- need_qual = true;
13216- break ;
13217- }
13218- }
13219- if (need_qual )
13220- break ;
13221- }
13222-
13223- /* Otherwise, qualify the name if not visible in search path */
13224- if (!need_qual )
13225- need_qual = !RelationIsVisible (relid );
13226-
13227- if (need_qual )
13228- nspname = get_namespace_name_or_temp (reltup -> relnamespace );
13229- else
13230- nspname = NULL ;
13231-
13232- result = quote_qualified_identifier (nspname , relname );
13233-
13234- ReleaseSysCache (tp );
13235-
13236- return result ;
13237- }
13238-
13239- /*
13240- * generate_qualified_relation_name
13241- * Compute the name to display for a relation specified by OID
13242- *
13243- * As above, but unconditionally schema-qualify the name.
13244- */
13245- static char *
13246- generate_qualified_relation_name (Oid relid )
13247- {
13248- HeapTuple tp ;
13249- Form_pg_class reltup ;
13250- char * relname ;
13251- char * nspname ;
13252- char * result ;
13253-
13254- tp = SearchSysCache1 (RELOID , ObjectIdGetDatum (relid ));
13255- if (!HeapTupleIsValid (tp ))
13256- elog (ERROR , "cache lookup failed for relation %u" , relid );
13257- reltup = (Form_pg_class ) GETSTRUCT (tp );
13258- relname = NameStr (reltup -> relname );
13259-
13260- nspname = get_namespace_name_or_temp (reltup -> relnamespace );
13261- if (!nspname )
13262- elog (ERROR , "cache lookup failed for namespace %u" ,
13263- reltup -> relnamespace );
13264-
13265- result = quote_qualified_identifier (nspname , relname );
13266-
13267- ReleaseSysCache (tp );
13268-
13269- return result ;
13270- }
1327113262
1327213263/*
1327313264 * generate_function_name
@@ -13307,6 +13298,10 @@ generate_function_name(Oid funcid, int nargs, List *argnames, Oid *argtypes,
1330713298 Oid * p_true_typeids ;
1330813299 bool force_qualify = false;
1330913300
13301+ result = pgduckdb_function_name (funcid , use_variadic_p );
13302+ if (result )
13303+ return result ;
13304+
1331013305 proctup = SearchSysCache1 (PROCOID , ObjectIdGetDatum (funcid ));
1331113306 if (!HeapTupleIsValid (proctup ))
1331213307 elog (ERROR , "cache lookup failed for function %u" , funcid );
@@ -13743,3 +13738,5 @@ get_range_partbound_string(List *bound_datums)
1374313738
1374413739 return buf .data ;
1374513740}
13741+
13742+ #endif
0 commit comments