11/*-------------------------------------------------------------------------
22 *
3- * ruleutils .c
3+ * pg_ruleutils_18 .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 >= 180000 && PG_VERSION_NUM < 190000
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 ,
@@ -5773,6 +5777,9 @@ get_with_clause(Query *query, deparse_context *context)
57735777 if (query -> cteList == NIL )
57745778 return ;
57755779
5780+ bool previous_outermost_query = outermost_query ;
5781+ outermost_query = false;
5782+
57765783 if (PRETTY_INDENT (context ))
57775784 {
57785785 context -> indentLevel += PRETTYINDENT_STD ;
@@ -5896,6 +5903,8 @@ get_with_clause(Query *query, deparse_context *context)
58965903 }
58975904 else
58985905 appendStringInfoChar (buf , ' ' );
5906+
5907+ outermost_query = previous_outermost_query ;
58995908}
59005909
59015910/* ----------
@@ -6240,12 +6249,23 @@ get_target_list(List *targetList, deparse_context *context)
62406249
62416250 sep = " " ;
62426251 colno = 0 ;
6252+
6253+ StarReconstructionContext star_reconstruction_context = {0 };
6254+ star_reconstruction_context .target_list = targetList ;
6255+
6256+ bool outermost_targetlist = outermost_query ;
6257+ outermost_query = false;
6258+
62436259 foreach (l , targetList )
62446260 {
62456261 TargetEntry * tle = (TargetEntry * ) lfirst (l );
62466262 char * colname ;
62476263 char * attname ;
62486264
6265+ if (pgduckdb_reconstruct_star_step (& star_reconstruction_context , l )) {
6266+ continue ;
6267+ }
6268+
62496269 if (tle -> resjunk )
62506270 continue ; /* ignore junk entries */
62516271
@@ -6270,8 +6290,10 @@ get_target_list(List *targetList, deparse_context *context)
62706290 * directly so that we can tell it to do the right thing, and so that
62716291 * we can get the attribute name which is the default AS label.
62726292 */
6293+ Var * var = NULL ;
62736294 if (tle -> expr && (IsA (tle -> expr , Var )))
62746295 {
6296+ var = (Var * ) tle -> expr ;
62756297 attname = get_variable ((Var * ) tle -> expr , 0 , true, context );
62766298 }
62776299 else
@@ -6298,8 +6320,33 @@ get_target_list(List *targetList, deparse_context *context)
62986320 else
62996321 colname = tle -> resname ;
63006322
6323+ /*
6324+ * This makes sure we don't add Postgres its bad default alias to the
6325+ * duckdb.row type.
6326+ */
6327+ bool duckdb_skip_as = pgduckdb_var_is_duckdb_row (var );
6328+
6329+ /*
6330+ * For r['abc'] expressions we don't want the column name to be r, but
6331+ * instead we want it to be "abc". We can only to do this for the
6332+ * target list of the outside most query though to make sure references
6333+ * to the column name are still valid.
6334+ */
6335+ if (!duckdb_skip_as && outermost_targetlist ) {
6336+ Var * subscript_var = pgduckdb_duckdb_row_subscript_var (tle -> expr );
6337+ if (subscript_var ) {
6338+ /*
6339+ * This cannot be moved to pgduckdb_ruleutils, because of
6340+ * the reliance on the non-public deparse_namespace type.
6341+ */
6342+ deparse_namespace * dpns = (deparse_namespace * ) list_nth (context -> namespaces ,
6343+ subscript_var -> varlevelsup );
6344+ duckdb_skip_as = !pgduckdb_subscript_has_custom_alias (dpns -> plan , dpns -> rtable , subscript_var , colname );
6345+ }
6346+ }
6347+
63016348 /* Show AS unless the column's name is correct as-is */
6302- if (colname ) /* resname could be NULL */
6349+ if (colname && ! duckdb_skip_as ) /* resname could be NULL */
63036350 {
63046351 if (attname == NULL || strcmp (attname , colname ) != 0 )
63056352 appendStringInfo (& targetbuf , " AS %s" , quote_identifier (colname ));
@@ -6999,6 +7046,16 @@ get_insert_query_def(Query *query, deparse_context *context)
69997046 if (tle -> resjunk )
70007047 continue ; /* ignore junk entries */
70017048
7049+ /*
7050+ * If it's an INSERT ... SELECT or multi-row VALUES, the entry
7051+ * with the default value is ignored unless it is specified
7052+ */
7053+ if (values_rte || select_rte )
7054+ {
7055+ if (!pgduckdb_is_not_default_expr ((Node * ) tle , NULL ))
7056+ continue ;
7057+ }
7058+
70027059 appendStringInfoString (buf , sep );
70037060 sep = ", " ;
70047061
@@ -7791,6 +7848,11 @@ get_variable(Var *var, int levelsup, bool istoplevel, deparse_context *context)
77917848 if (attnum > colinfo -> num_cols )
77927849 elog (ERROR , "invalid attnum %d for relation \"%s\"" ,
77937850 attnum , rte -> eref -> aliasname );
7851+
7852+ if (pgduckdb_var_is_duckdb_row (var )) {
7853+ return pgduckdb_write_row_refname (context -> buf , refname , istoplevel );
7854+ }
7855+
77947856 attname = colinfo -> colnames [attnum - 1 ];
77957857
77967858 /*
@@ -9354,8 +9416,9 @@ get_rule_expr(Node *node, deparse_context *context,
93549416 }
93559417 else
93569418 {
9419+ SubscriptingRef * new_sbsref = pgduckdb_strip_first_subscript (sbsref , context -> buf );
93579420 /* Just an ordinary container fetch, so print subscripts */
9358- printSubscripts (sbsref , context );
9421+ printSubscripts (new_sbsref , context );
93599422 }
93609423 }
93619424 break ;
@@ -10736,12 +10799,13 @@ get_oper_expr(OpExpr *expr, deparse_context *context)
1073610799 Node * arg1 = (Node * ) linitial (args );
1073710800 Node * arg2 = (Node * ) lsecond (args );
1073810801
10802+ char * op_name = generate_operator_name (opno , exprType (arg1 ), exprType (arg2 ));
10803+ void * ctx = pg_duckdb_get_oper_expr_make_ctx (op_name , & arg1 , & arg2 );
10804+ pg_duckdb_get_oper_expr_prefix (buf , ctx );
1073910805 get_rule_expr_paren (arg1 , context , true, (Node * ) expr );
10740- appendStringInfo (buf , " %s " ,
10741- generate_operator_name (opno ,
10742- exprType (arg1 ),
10743- exprType (arg2 )));
10806+ pg_duckdb_get_oper_expr_middle (buf , ctx );
1074410807 get_rule_expr_paren (arg2 , context , true, (Node * ) expr );
10808+ pg_duckdb_get_oper_expr_suffix (buf , ctx );
1074510809 }
1074610810 else
1074710811 {
@@ -11425,6 +11489,10 @@ get_coercion_expr(Node *arg, deparse_context *context,
1142511489 appendStringInfoChar (buf , ')' );
1142611490 }
1142711491
11492+ if (pgduckdb_is_fake_type (resulttype )) {
11493+ return ;
11494+ }
11495+
1142811496 /*
1142911497 * Never emit resulttype(arg) functional notation. A pg_proc entry could
1143011498 * take precedence, and a resulttype in pg_temp would require schema
@@ -11460,6 +11528,8 @@ get_const_expr(Const *constval, deparse_context *context, int showtype)
1146011528 char * extval ;
1146111529 bool needlabel = false;
1146211530
11531+ showtype = pgduckdb_show_type (constval , showtype );
11532+
1146311533 if (constval -> constisnull )
1146411534 {
1146511535 /*
@@ -12378,6 +12448,9 @@ get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
1237812448 break ;
1237912449 case RTE_SUBQUERY :
1238012450 /* Subquery RTE */
12451+ if (pgduckdb_replace_subquery_with_view (rte -> subquery , buf )) {
12452+ break ;
12453+ }
1238112454 appendStringInfoChar (buf , '(' );
1238212455 get_query_def (rte -> subquery , buf , context -> namespaces , NULL ,
1238312456 true,
@@ -12500,8 +12573,18 @@ get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
1250012573 /* Print the relation alias, if needed */
1250112574 get_rte_alias (rte , varno , false, context );
1250212575
12576+ if (pgduckdb_func_returns_duckdb_row (rtfunc1 )) {
12577+ /*
12578+ * We never want to print column aliases for functions that return
12579+ * a duckdb.row. The common pattern is for people to not provide an
12580+ * explicit column alias (i.e. "r" becomes "r(r)"). This obviously
12581+ * is a naming collision and DuckDB resolves that in the opposite
12582+ * way that we want. Never adding column aliases for duckdb.row
12583+ * avoids this conflict.
12584+ */
12585+ }
1250312586 /* Print the column definitions or aliases, if needed */
12504- if (rtfunc1 && rtfunc1 -> funccolnames != NIL )
12587+ else if (rtfunc1 && rtfunc1 -> funccolnames != NIL )
1250512588 {
1250612589 /* Reconstruct the columndef list, which is also the aliases */
1250712590 get_from_clause_coldeflist (rtfunc1 , colinfo , context );
@@ -12827,6 +12910,10 @@ get_tablesample_def(TableSampleClause *tablesample, deparse_context *context)
1282712910 if (nargs ++ > 0 )
1282812911 appendStringInfoString (buf , ", " );
1282912912 get_rule_expr ((Node * ) lfirst (l ), context , false);
12913+ const char * tsm_name = generate_function_name (tablesample -> tsmhandler , 1 ,
12914+ NIL , argtypes ,
12915+ false, NULL , EXPR_KIND_NONE );
12916+ pgduckdb_add_tablesample_percent (tsm_name , buf , list_length (tablesample -> args ));
1283012917 }
1283112918 appendStringInfoChar (buf , ')' );
1283212919
@@ -13129,102 +13216,6 @@ get_relation_name(Oid relid)
1312913216 return relname ;
1313013217}
1313113218
13132- /*
13133- * generate_relation_name
13134- * Compute the name to display for a relation specified by OID
13135- *
13136- * The result includes all necessary quoting and schema-prefixing.
13137- *
13138- * If namespaces isn't NIL, it must be a list of deparse_namespace nodes.
13139- * We will forcibly qualify the relation name if it equals any CTE name
13140- * visible in the namespace list.
13141- */
13142- static char *
13143- generate_relation_name (Oid relid , List * namespaces )
13144- {
13145- HeapTuple tp ;
13146- Form_pg_class reltup ;
13147- bool need_qual ;
13148- ListCell * nslist ;
13149- char * relname ;
13150- char * nspname ;
13151- char * result ;
13152-
13153- tp = SearchSysCache1 (RELOID , ObjectIdGetDatum (relid ));
13154- if (!HeapTupleIsValid (tp ))
13155- elog (ERROR , "cache lookup failed for relation %u" , relid );
13156- reltup = (Form_pg_class ) GETSTRUCT (tp );
13157- relname = NameStr (reltup -> relname );
13158-
13159- /* Check for conflicting CTE name */
13160- need_qual = false;
13161- foreach (nslist , namespaces )
13162- {
13163- deparse_namespace * dpns = (deparse_namespace * ) lfirst (nslist );
13164- ListCell * ctlist ;
13165-
13166- foreach (ctlist , dpns -> ctes )
13167- {
13168- CommonTableExpr * cte = (CommonTableExpr * ) lfirst (ctlist );
13169-
13170- if (strcmp (cte -> ctename , relname ) == 0 )
13171- {
13172- need_qual = true;
13173- break ;
13174- }
13175- }
13176- if (need_qual )
13177- break ;
13178- }
13179-
13180- /* Otherwise, qualify the name if not visible in search path */
13181- if (!need_qual )
13182- need_qual = !RelationIsVisible (relid );
13183-
13184- if (need_qual )
13185- nspname = get_namespace_name_or_temp (reltup -> relnamespace );
13186- else
13187- nspname = NULL ;
13188-
13189- result = quote_qualified_identifier (nspname , relname );
13190-
13191- ReleaseSysCache (tp );
13192-
13193- return result ;
13194- }
13195-
13196- /*
13197- * generate_qualified_relation_name
13198- * Compute the name to display for a relation specified by OID
13199- *
13200- * As above, but unconditionally schema-qualify the name.
13201- */
13202- static char *
13203- generate_qualified_relation_name (Oid relid )
13204- {
13205- HeapTuple tp ;
13206- Form_pg_class reltup ;
13207- char * relname ;
13208- char * nspname ;
13209- char * result ;
13210-
13211- tp = SearchSysCache1 (RELOID , ObjectIdGetDatum (relid ));
13212- if (!HeapTupleIsValid (tp ))
13213- elog (ERROR , "cache lookup failed for relation %u" , relid );
13214- reltup = (Form_pg_class ) GETSTRUCT (tp );
13215- relname = NameStr (reltup -> relname );
13216-
13217- nspname = get_namespace_name_or_temp (reltup -> relnamespace );
13218- if (!nspname )
13219- elog (ERROR , "cache lookup failed for namespace %u" ,
13220- reltup -> relnamespace );
13221-
13222- result = quote_qualified_identifier (nspname , relname );
13223-
13224- ReleaseSysCache (tp );
13225-
13226- return result ;
13227- }
1322813219
1322913220/*
1323013221 * generate_function_name
@@ -13263,6 +13254,10 @@ generate_function_name(Oid funcid, int nargs, List *argnames, Oid *argtypes,
1326313254 Oid * p_true_typeids ;
1326413255 bool force_qualify = false;
1326513256
13257+ result = pgduckdb_function_name (funcid , use_variadic_p );
13258+ if (result )
13259+ return result ;
13260+
1326613261 proctup = SearchSysCache1 (PROCOID , ObjectIdGetDatum (funcid ));
1326713262 if (!HeapTupleIsValid (proctup ))
1326813263 elog (ERROR , "cache lookup failed for function %u" , funcid );
@@ -13697,3 +13692,5 @@ get_range_partbound_string(List *bound_datums)
1369713692
1369813693 return buf -> data ;
1369913694}
13695+
13696+ #endif
0 commit comments