From 014b34fdf30e96d49c2927253ed59547379d5755 Mon Sep 17 00:00:00 2001 From: Harsh Dubey Date: Tue, 10 Jun 2025 13:42:52 +0000 Subject: [PATCH 1/4] Added support for openxml with WITH clause Signed-off-by: Harsh Dubey --- src/backend/nodes/gen_node_support.pl | 2 +- src/backend/nodes/nodeFuncs.c | 18 ++++++++++++++++++ src/backend/parser/parse_clause.c | 22 ++++++++++++++++++++++ src/include/nodes/parsenodes.h | 16 ++++++++++++++++ src/include/parser/parse_clause.h | 6 ++++++ 5 files changed, 63 insertions(+), 1 deletion(-) diff --git a/src/backend/nodes/gen_node_support.pl b/src/backend/nodes/gen_node_support.pl index f667e86240e..fde1824a142 100644 --- a/src/backend/nodes/gen_node_support.pl +++ b/src/backend/nodes/gen_node_support.pl @@ -107,7 +107,7 @@ sub elem # ABI stability during development. my $last_nodetag = 'WindowObjectData'; -my $last_nodetag_no = 475; +my $last_nodetag_no = 476; # output file names my @output_files; diff --git a/src/backend/nodes/nodeFuncs.c b/src/backend/nodes/nodeFuncs.c index 6256d43235a..0b870bd6fef 100644 --- a/src/backend/nodes/nodeFuncs.c +++ b/src/backend/nodes/nodeFuncs.c @@ -4507,6 +4507,24 @@ raw_expression_tree_walker_impl(Node *node, return true; } break; + case T_Openxml_expr: + { + Openxml_expr *expr = (Openxml_expr *) node; + + if (WALK(expr->tsql_docid)) + return true; + if (WALK(expr->rowexpr)) + return true; + if (WALK(expr->tsql_flag)) + return true; + if (WALK(expr->columns)) + return true; + if (WALK(expr->table_ref)) + return true; + if (WALK(expr->alias)) + return true; + } + break; case T_RangeTableFuncCol: { RangeTableFuncCol *rtfc = (RangeTableFuncCol *) node; diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c index a823c1b370e..881408b1984 100644 --- a/src/backend/parser/parse_clause.c +++ b/src/backend/parser/parse_clause.c @@ -55,6 +55,7 @@ tle_name_comparison_hook_type tle_name_comparison_hook = NULL; sortby_nulls_hook_type sortby_nulls_hook = NULL; optimize_explicit_cast_hook_type optimize_explicit_cast_hook = NULL; +transformFromClauseItem_hook_type transformFromClauseItem_hook = NULL; static int extractRemainingColumns(ParseState *pstate, ParseNamespaceColumn *src_nscolumns, @@ -908,6 +909,13 @@ transformRangeTableFunc(ParseState *pstate, RangeTableFunc *rtf) tf, rtf->alias, is_lateral, true); } +/* Wrapper function that calls the static transformRangeTableFunc function */ +ParseNamespaceItem * +bbf_transformRangeTableFunc(ParseState *pstate, RangeTableFunc *rtf) +{ + return transformRangeTableFunc(pstate, rtf); +} + /* * transformRangeTableSample --- transform a TABLESAMPLE clause * @@ -1068,6 +1076,20 @@ transformFromClauseItem(ParseState *pstate, Node *n, /* Guard against stack overflow due to overly deep subtree */ check_stack_depth(); + /* + * Call the transformFromClauseItem hook if one is registered. + * If the hook returns a non-NULL value, use that as the result and skip + * the standard transformation process. Otherwise, continue with normal + * transformation. + */ + if (transformFromClauseItem_hook) + { + Node *result; + result = transformFromClauseItem_hook(pstate, n, top_nsitem, namespace); + if (result != NULL) + return result; + } + if (IsA(n, RangeVar)) { /* Plain relation reference, or perhaps a CTE reference */ diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index ef23f41864b..e74148095d2 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -666,6 +666,22 @@ typedef struct RangeTableFunc ParseLoc location; /* token location, or -1 if unknown */ } RangeTableFunc; +/* + * Openxml_expr - Custom node for OPENXML function in T-SQL + * This structure represents the OPENXML function call in T-SQL syntax + */ +typedef struct Openxml_expr +{ + NodeTag type; + Node *tsql_docid; /* Document ID */ + Node *rowexpr; /* XPath expression for row selection */ + Node *tsql_flag; /* Flag controlling XPath generation */ + List *columns; /* List of column definitions */ + RangeVar *table_ref; /* Reference to a table for WITH TABLE syntax */ + Alias *alias; /* Table alias & optional column aliases */ + ParseLoc location; /* Token location, or -1 if unknown */ +} Openxml_expr; + /* * RangeTableFuncCol - one column in a RangeTableFunc->columns * diff --git a/src/include/parser/parse_clause.h b/src/include/parser/parse_clause.h index d307e4dbdc9..791442ebad1 100644 --- a/src/include/parser/parse_clause.h +++ b/src/include/parser/parse_clause.h @@ -62,4 +62,10 @@ extern PGDLLEXPORT optimize_explicit_cast_hook_type optimize_explicit_cast_hook; /* functions in parse_jsontable.c */ extern ParseNamespaceItem *transformJsonTable(ParseState *pstate, JsonTable *jt); +/* Hook for custom FROM clause item transformation */ +typedef Node* (*transformFromClauseItem_hook_type)(ParseState *pstate, Node *n,ParseNamespaceItem **top_nsitem,List **namespace); +extern PGDLLIMPORT transformFromClauseItem_hook_type transformFromClauseItem_hook; + +/* */ +extern ParseNamespaceItem *bbf_transformRangeTableFunc(ParseState *pstate, RangeTableFunc *rtf); #endif /* PARSE_CLAUSE_H */ From 85f35b3aa66d0b38bd1ceb1f21b9496d744f3bf4 Mon Sep 17 00:00:00 2001 From: Harsh Dubey Date: Thu, 19 Jun 2025 13:20:03 +0000 Subject: [PATCH 2/4] New approach for openxml Signed-off-by: Harsh Dubey --- src/backend/nodes/gen_node_support.pl | 2 +- src/backend/nodes/nodeFuncs.c | 18 ------------------ src/backend/parser/parse_clause.c | 27 +++++---------------------- src/include/nodes/parsenodes.h | 16 ---------------- src/include/parser/parse_clause.h | 7 ++----- 5 files changed, 8 insertions(+), 62 deletions(-) diff --git a/src/backend/nodes/gen_node_support.pl b/src/backend/nodes/gen_node_support.pl index fde1824a142..f667e86240e 100644 --- a/src/backend/nodes/gen_node_support.pl +++ b/src/backend/nodes/gen_node_support.pl @@ -107,7 +107,7 @@ sub elem # ABI stability during development. my $last_nodetag = 'WindowObjectData'; -my $last_nodetag_no = 476; +my $last_nodetag_no = 475; # output file names my @output_files; diff --git a/src/backend/nodes/nodeFuncs.c b/src/backend/nodes/nodeFuncs.c index 0b870bd6fef..6256d43235a 100644 --- a/src/backend/nodes/nodeFuncs.c +++ b/src/backend/nodes/nodeFuncs.c @@ -4507,24 +4507,6 @@ raw_expression_tree_walker_impl(Node *node, return true; } break; - case T_Openxml_expr: - { - Openxml_expr *expr = (Openxml_expr *) node; - - if (WALK(expr->tsql_docid)) - return true; - if (WALK(expr->rowexpr)) - return true; - if (WALK(expr->tsql_flag)) - return true; - if (WALK(expr->columns)) - return true; - if (WALK(expr->table_ref)) - return true; - if (WALK(expr->alias)) - return true; - } - break; case T_RangeTableFuncCol: { RangeTableFuncCol *rtfc = (RangeTableFuncCol *) node; diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c index 881408b1984..31443245aef 100644 --- a/src/backend/parser/parse_clause.c +++ b/src/backend/parser/parse_clause.c @@ -55,7 +55,8 @@ tle_name_comparison_hook_type tle_name_comparison_hook = NULL; sortby_nulls_hook_type sortby_nulls_hook = NULL; optimize_explicit_cast_hook_type optimize_explicit_cast_hook = NULL; -transformFromClauseItem_hook_type transformFromClauseItem_hook = NULL; + +pre_transform_openxml_columns_hook_type pre_transform_openxml_columns_hook = NULL; static int extractRemainingColumns(ParseState *pstate, ParseNamespaceColumn *src_nscolumns, @@ -712,6 +713,9 @@ transformRangeTableFunc(ParseState *pstate, RangeTableFunc *rtf) constructName = "XMLTABLE"; docType = XMLOID; + if (pre_transform_openxml_columns_hook) + pre_transform_openxml_columns_hook(pstate, rtf); + /* * We make lateral_only names of this level visible, whether or not the * RangeTableFunc is explicitly marked LATERAL. This is needed for SQL @@ -909,13 +913,6 @@ transformRangeTableFunc(ParseState *pstate, RangeTableFunc *rtf) tf, rtf->alias, is_lateral, true); } -/* Wrapper function that calls the static transformRangeTableFunc function */ -ParseNamespaceItem * -bbf_transformRangeTableFunc(ParseState *pstate, RangeTableFunc *rtf) -{ - return transformRangeTableFunc(pstate, rtf); -} - /* * transformRangeTableSample --- transform a TABLESAMPLE clause * @@ -1076,20 +1073,6 @@ transformFromClauseItem(ParseState *pstate, Node *n, /* Guard against stack overflow due to overly deep subtree */ check_stack_depth(); - /* - * Call the transformFromClauseItem hook if one is registered. - * If the hook returns a non-NULL value, use that as the result and skip - * the standard transformation process. Otherwise, continue with normal - * transformation. - */ - if (transformFromClauseItem_hook) - { - Node *result; - result = transformFromClauseItem_hook(pstate, n, top_nsitem, namespace); - if (result != NULL) - return result; - } - if (IsA(n, RangeVar)) { /* Plain relation reference, or perhaps a CTE reference */ diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index e74148095d2..ef23f41864b 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -666,22 +666,6 @@ typedef struct RangeTableFunc ParseLoc location; /* token location, or -1 if unknown */ } RangeTableFunc; -/* - * Openxml_expr - Custom node for OPENXML function in T-SQL - * This structure represents the OPENXML function call in T-SQL syntax - */ -typedef struct Openxml_expr -{ - NodeTag type; - Node *tsql_docid; /* Document ID */ - Node *rowexpr; /* XPath expression for row selection */ - Node *tsql_flag; /* Flag controlling XPath generation */ - List *columns; /* List of column definitions */ - RangeVar *table_ref; /* Reference to a table for WITH TABLE syntax */ - Alias *alias; /* Table alias & optional column aliases */ - ParseLoc location; /* Token location, or -1 if unknown */ -} Openxml_expr; - /* * RangeTableFuncCol - one column in a RangeTableFunc->columns * diff --git a/src/include/parser/parse_clause.h b/src/include/parser/parse_clause.h index 791442ebad1..a57c2c46488 100644 --- a/src/include/parser/parse_clause.h +++ b/src/include/parser/parse_clause.h @@ -62,10 +62,7 @@ extern PGDLLEXPORT optimize_explicit_cast_hook_type optimize_explicit_cast_hook; /* functions in parse_jsontable.c */ extern ParseNamespaceItem *transformJsonTable(ParseState *pstate, JsonTable *jt); -/* Hook for custom FROM clause item transformation */ -typedef Node* (*transformFromClauseItem_hook_type)(ParseState *pstate, Node *n,ParseNamespaceItem **top_nsitem,List **namespace); -extern PGDLLIMPORT transformFromClauseItem_hook_type transformFromClauseItem_hook; +typedef void (*pre_transform_openxml_columns_hook_type) (ParseState *pstate, RangeTableFunc *rtf); +extern PGDLLEXPORT pre_transform_openxml_columns_hook_type pre_transform_openxml_columns_hook; -/* */ -extern ParseNamespaceItem *bbf_transformRangeTableFunc(ParseState *pstate, RangeTableFunc *rtf); #endif /* PARSE_CLAUSE_H */ From 90175c254f6c5da5f7014e89c678d0467f032a4e Mon Sep 17 00:00:00 2001 From: Harsh Dubey Date: Fri, 20 Jun 2025 07:03:06 +0000 Subject: [PATCH 3/4] Added comments for more details Signed-off-by: Harsh Dubey --- src/backend/parser/parse_clause.c | 4 ++++ src/include/parser/parse_clause.h | 1 + 2 files changed, 5 insertions(+) diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c index 31443245aef..eef38d61bd9 100644 --- a/src/backend/parser/parse_clause.c +++ b/src/backend/parser/parse_clause.c @@ -713,6 +713,10 @@ transformRangeTableFunc(ParseState *pstate, RangeTableFunc *rtf) constructName = "XMLTABLE"; docType = XMLOID; + /* + * Hook to allow extensions to pre-process OPENXML column definitions + * before standard XMLTABLE transformation. + */ if (pre_transform_openxml_columns_hook) pre_transform_openxml_columns_hook(pstate, rtf); diff --git a/src/include/parser/parse_clause.h b/src/include/parser/parse_clause.h index a57c2c46488..575a21ae1a9 100644 --- a/src/include/parser/parse_clause.h +++ b/src/include/parser/parse_clause.h @@ -62,6 +62,7 @@ extern PGDLLEXPORT optimize_explicit_cast_hook_type optimize_explicit_cast_hook; /* functions in parse_jsontable.c */ extern ParseNamespaceItem *transformJsonTable(ParseState *pstate, JsonTable *jt); +/* Hook for preprocessing OPENXML column definitions before XMLTABLE transformation */ typedef void (*pre_transform_openxml_columns_hook_type) (ParseState *pstate, RangeTableFunc *rtf); extern PGDLLEXPORT pre_transform_openxml_columns_hook_type pre_transform_openxml_columns_hook; From cc434f3415dbe6746a1c693dd9d72a0dd7b101a6 Mon Sep 17 00:00:00 2001 From: Harsh Dubey Date: Wed, 25 Jun 2025 14:44:29 +0000 Subject: [PATCH 4/4] Added extra check of xmltable in the hook Signed-off-by: Harsh Dubey --- src/backend/parser/parse_clause.c | 2 +- src/include/parser/parse_clause.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c index eef38d61bd9..9247da6b2bd 100644 --- a/src/backend/parser/parse_clause.c +++ b/src/backend/parser/parse_clause.c @@ -717,7 +717,7 @@ transformRangeTableFunc(ParseState *pstate, RangeTableFunc *rtf) * Hook to allow extensions to pre-process OPENXML column definitions * before standard XMLTABLE transformation. */ - if (pre_transform_openxml_columns_hook) + if (pre_transform_openxml_columns_hook && tf->functype == TFT_XMLTABLE) pre_transform_openxml_columns_hook(pstate, rtf); /* diff --git a/src/include/parser/parse_clause.h b/src/include/parser/parse_clause.h index 575a21ae1a9..ca3e0d3eb2c 100644 --- a/src/include/parser/parse_clause.h +++ b/src/include/parser/parse_clause.h @@ -64,6 +64,6 @@ extern ParseNamespaceItem *transformJsonTable(ParseState *pstate, JsonTable *jt) /* Hook for preprocessing OPENXML column definitions before XMLTABLE transformation */ typedef void (*pre_transform_openxml_columns_hook_type) (ParseState *pstate, RangeTableFunc *rtf); -extern PGDLLEXPORT pre_transform_openxml_columns_hook_type pre_transform_openxml_columns_hook; +extern PGDLLIMPORT pre_transform_openxml_columns_hook_type pre_transform_openxml_columns_hook; #endif /* PARSE_CLAUSE_H */