From b1f3a60a5c5d4f061568deba91a01297dfbf4f16 Mon Sep 17 00:00:00 2001 From: Harsh Dubey Date: Tue, 10 Jun 2025 09:29:30 +0000 Subject: [PATCH 01/40] Added the changes of sp_xml_preparedocument and sp_xml_removedocument procedures Signed-off-by: Harsh Dubey --- .../babelfishpg_tsql/sql/sys_procedures.sql | 17 + .../babelfishpg_tsql--5.1.0--5.2.0.sql | 45 ++ contrib/babelfishpg_tsql/src/pltsql.h | 5 + contrib/babelfishpg_tsql/src/procedures.c | 648 ++++++++++++++++++ contrib/babelfishpg_tsql/src/session.c | 1 + .../sp_xml_preparedocument-vu-cleanup.out | 11 + .../sp_xml_preparedocument-vu-prepare.out | 17 + .../sp_xml_preparedocument-vu-verify.out | 495 +++++++++++++ .../sp_xml_removedocument-vu-verify.out | 38 + .../xml/sp_xml_preparedocument-vu-cleanup.sql | 11 + .../xml/sp_xml_preparedocument-vu-prepare.sql | 17 + .../xml/sp_xml_preparedocument-vu-verify.sql | 312 +++++++++ .../xml/sp_xml_removedocument-vu-verify.sql | 22 + test/JDBC/upgrade/13_4/schedule | 2 + test/JDBC/upgrade/13_5/schedule | 2 + test/JDBC/upgrade/13_6/schedule | 2 + test/JDBC/upgrade/13_7/schedule | 2 + test/JDBC/upgrade/13_8/schedule | 2 + test/JDBC/upgrade/13_9/schedule | 2 + test/JDBC/upgrade/14_10/schedule | 2 + test/JDBC/upgrade/14_11/schedule | 2 + test/JDBC/upgrade/14_12/schedule | 2 + test/JDBC/upgrade/14_13/schedule | 2 + test/JDBC/upgrade/14_15/schedule | 2 + test/JDBC/upgrade/14_17/schedule | 2 + test/JDBC/upgrade/14_3/schedule | 2 + test/JDBC/upgrade/14_5/schedule | 2 + test/JDBC/upgrade/14_6/schedule | 2 + test/JDBC/upgrade/14_7/schedule | 2 + test/JDBC/upgrade/14_8/schedule | 2 + test/JDBC/upgrade/14_9/schedule | 2 + test/JDBC/upgrade/15_1/schedule | 2 + test/JDBC/upgrade/15_10/schedule | 2 + test/JDBC/upgrade/15_12/schedule | 2 + test/JDBC/upgrade/15_2/schedule | 2 + test/JDBC/upgrade/15_3/schedule | 2 + test/JDBC/upgrade/15_4/schedule | 2 + test/JDBC/upgrade/15_5/schedule | 2 + test/JDBC/upgrade/15_6/schedule | 2 + test/JDBC/upgrade/15_7/schedule | 2 + test/JDBC/upgrade/15_8/schedule | 2 + test/JDBC/upgrade/16_1/schedule | 2 + test/JDBC/upgrade/16_10/schedule | 2 + test/JDBC/upgrade/16_2/schedule | 2 + test/JDBC/upgrade/16_3/schedule | 2 + test/JDBC/upgrade/16_4/schedule | 2 + test/JDBC/upgrade/16_6/schedule | 2 + test/JDBC/upgrade/16_9/schedule | 2 + test/JDBC/upgrade/latest/schedule | 2 + .../expected_create.out | 1 - 50 files changed, 1711 insertions(+), 1 deletion(-) create mode 100644 test/JDBC/expected/sp_xml_preparedocument-vu-cleanup.out create mode 100644 test/JDBC/expected/sp_xml_preparedocument-vu-prepare.out create mode 100644 test/JDBC/expected/sp_xml_preparedocument-vu-verify.out create mode 100644 test/JDBC/expected/sp_xml_removedocument-vu-verify.out create mode 100644 test/JDBC/input/xml/sp_xml_preparedocument-vu-cleanup.sql create mode 100644 test/JDBC/input/xml/sp_xml_preparedocument-vu-prepare.sql create mode 100644 test/JDBC/input/xml/sp_xml_preparedocument-vu-verify.sql create mode 100644 test/JDBC/input/xml/sp_xml_removedocument-vu-verify.sql diff --git a/contrib/babelfishpg_tsql/sql/sys_procedures.sql b/contrib/babelfishpg_tsql/sql/sys_procedures.sql index 8734c5882e7..efc2d96a065 100644 --- a/contrib/babelfishpg_tsql/sql/sys_procedures.sql +++ b/contrib/babelfishpg_tsql/sql/sys_procedures.sql @@ -333,3 +333,20 @@ GRANT EXECUTE on PROCEDURE sys.sp_enum_oledb_providers() TO PUBLIC; CREATE OR REPLACE PROCEDURE sys.sp_reset_connection() AS 'babelfishpg_tsql', 'sp_reset_connection_internal' LANGUAGE C; GRANT EXECUTE ON PROCEDURE sys.sp_reset_connection() TO PUBLIC; + +CREATE OR REPLACE PROCEDURE sys.sp_xml_preparedocument( INOUT "@hdoc" INTEGER, + IN "@xmltext" sys.VARCHAR DEFAULT NULL, + IN "@xpath_namespaces" sys.VARCHAR DEFAULT NULL ) +AS 'babelfishpg_tsql', 'sp_xml_preparedocument' +LANGUAGE C; + +GRANT EXECUTE ON PROCEDURE sys.sp_xml_preparedocument( INOUT "@hdoc" INTEGER, + IN "@xmltext" sys.VARCHAR , + IN "@xpath_namespaces" sys.VARCHAR ) +TO PUBLIC; + +CREATE OR REPLACE PROCEDURE sys.sp_xml_removedocument( IN "@hdoc" INTEGER ) +AS 'babelfishpg_tsql', 'sp_xml_removedocument' +LANGUAGE C; + +GRANT EXECUTE ON PROCEDURE sys.sp_xml_removedocument( IN INTEGER ) TO PUBLIC; \ No newline at end of file diff --git a/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--5.1.0--5.2.0.sql b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--5.1.0--5.2.0.sql index dad8aa405a2..d0db8fd8b53 100644 --- a/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--5.1.0--5.2.0.sql +++ b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--5.1.0--5.2.0.sql @@ -1553,6 +1553,51 @@ GRANT SELECT ON sys.dm_os_sys_info TO PUBLIC; -- Please have this be one of the last statements executed in this upgrade script. DROP PROCEDURE sys.babelfish_drop_deprecated_object(varchar, varchar, varchar); +-- BBF_XML_HANDLES +-- This catalog table stores the metadata of the XML handles generated across various sessions. +CREATE TABLE sys.babelfish_xml_handles ( + session_id INT NOT NULL, -- The Session ID of the session that holds this XML document handle. + document_id INT NOT NULL, -- XML document handle ID returned by sp_xml_preparedocument. + namespace_document_id INT NULL, -- Internal handle ID assigned to xpath_namespaces (NULL if there is no namespace document.) + Xml_content XML, -- The given XML doc stored in xml format + NamespaceDefinitions XML, -- The given xpath_namespaces in xml format + original_document_size_bytes BIGINT NULL, -- Size of the original XML document in bytes. + original_namespace_document_size_bytes BIGINT NULL, -- Size of the original XML namespace document, in bytes. NULL if there is no namespace document. + sql_handle BYTEA NULL, + statement_start_offset INT NULL, + statement_end_offset INT NULL, + num_openxml_calls BIGINT NULL, -- Number of OPENXML calls with this document handle. + row_count BIGINT NULL, -- Number of rows returned by all previous OPENXML calls for this document handle. + creation_time sys.datetime NULL, --Timestamp when sp_xml_preparedocument was called. + openxml_last_calltime sys.datetime NULL ,-- Timestamp of the last OPENXML call + PRIMARY KEY(session_id, document_id) +); + +-- SEQUENCE to maintain the ID of XML handles. +CREATE SEQUENCE sys.babelfish_xml_handles_seq START 1 INCREMENT 2 MAXVALUE 2147483647 CYCLE; + +GRANT SELECT ON sys.babelfish_xml_handles TO PUBLIC; + +CREATE OR REPLACE PROCEDURE sys.sp_xml_preparedocument( + INOUT "@hdoc" INTEGER, + IN "@xmltext" sys.VARCHAR DEFAULT NULL, + IN "@xpath_namespaces" sys.VARCHAR DEFAULT NULL +) +AS 'babelfishpg_tsql', 'sp_xml_preparedocument' +LANGUAGE C; +GRANT EXECUTE ON PROCEDURE sys.sp_xml_preparedocument( + INOUT INTEGER, IN sys.varchar, IN sys.varchar +) TO PUBLIC; + +CREATE OR REPLACE PROCEDURE sys.sp_xml_removedocument( + IN "@hdoc" INTEGER +) +AS 'babelfishpg_tsql', 'sp_xml_removedocument' +LANGUAGE C; +GRANT EXECUTE ON PROCEDURE sys.sp_xml_removedocument( + IN INTEGER +) TO PUBLIC; + -- After upgrade, always run analyze for all babelfish catalogs. CALL sys.analyze_babelfish_catalogs(); -- Reset search_path to not affect any subsequent scripts diff --git a/contrib/babelfishpg_tsql/src/pltsql.h b/contrib/babelfishpg_tsql/src/pltsql.h index b9a8a447423..58d3df6feda 100644 --- a/contrib/babelfishpg_tsql/src/pltsql.h +++ b/contrib/babelfishpg_tsql/src/pltsql.h @@ -1810,6 +1810,10 @@ typedef struct PLtsql_protocol_plugin char **tvp_type_name, char **tvp_type_schema_name); int32_t (*get_tds_numeric_get_typmod) (Numeric num); + + + int32 (*get_numeric_typmod_from_exp) (Plan *plan, Node *expr); + int32 (*get_numeric_typmod_from_exp) (Plan *plan, Node *expr, bool *found); /* Session level GUCs */ bool quoted_identifier; bool arithabort; @@ -2308,6 +2312,7 @@ int execute_sp_cursoroption(int cursor_handle, int code, int value); int execute_sp_cursoroption2(int cursor_handle, int code, const char *value); int execute_sp_cursorclose(int cursor_handle); void reset_cached_cursor(void); +void reset_cached_xml_handle(void); /* * Functions in string.c diff --git a/contrib/babelfishpg_tsql/src/procedures.c b/contrib/babelfishpg_tsql/src/procedures.c index a6ffb65b8fd..09387a26e22 100644 --- a/contrib/babelfishpg_tsql/src/procedures.c +++ b/contrib/babelfishpg_tsql/src/procedures.c @@ -20,6 +20,7 @@ #include "catalog/indexing.h" #include "commands/defrem.h" #include "commands/prepare.h" +#include "commands/tablecmds.h" #include "common/string.h" #include "executor/spi.h" #include "foreign/foreign.h" @@ -47,8 +48,11 @@ #include "tcop/tcopprot.h" #include "tcop/utility.h" #include "tsearch/ts_locale.h" +#include "utils/xml.h" +#include "common/md5.h" #include "catalog.h" +#include "catalog/toasting.h" #include "extendedproperty.h" #include "multidb.h" #include "session.h" @@ -78,6 +82,8 @@ PG_FUNCTION_INFO_V1(sp_execute_postgresql); PG_FUNCTION_INFO_V1(sp_enum_oledb_providers_internal); PG_FUNCTION_INFO_V1(sp_reset_connection_internal); PG_FUNCTION_INFO_V1(sp_renamedb_internal); +PG_FUNCTION_INFO_V1(sp_xml_preparedocument); +PG_FUNCTION_INFO_V1(sp_xml_removedocument); extern void delete_cached_batch(int handle); extern InlineCodeBlockArgs *create_args(int numargs); @@ -108,6 +114,16 @@ bool sp_describe_first_result_set_inprogress = false; char *orig_proc_funcname = NULL; static bool is_supported_case_sp_describe_undeclared_parameters = true; +const int XML_HANDLE_COUNTER_START = 0; +const int XML_HANDLE_COUNTER_INVALID = INT_MAX / 2; +static int current_xml_handle_counter; +Bitmapset *active_xml_handles_counter = NULL; +static char *xml_handle_temp_table_name = NULL; +int get_next_xml_handle_counter(void); +void create_xml_handle_temp_table(void); +void delete_xml_handle_entry(int handle); +int insert_xml_handle_entry(xmltype *xml_data,xmltype *ns_data, int xml_data_length, int ns_data_length); + /* server options and their default values for babelfish_server_options catalog insert */ char * srvOptions_optname[BBF_SERVERS_DEF_NUM_COLS - 1] = {"query timeout", "connect timeout"}; char * srvOptions_optvalue[BBF_SERVERS_DEF_NUM_COLS - 1] = {"0", "0"}; @@ -4290,3 +4306,635 @@ sp_reset_connection_internal(PG_FUNCTION_ARGS) PG_RETURN_VOID(); } + +/* + * get_next_xml_handle_counter - Allocates unique XML handle counters using circular allocation strategy. + * + * This function manages XML document handles by tracking them in a bitmap set. + * It increments the current handle counter and verifies its availability through two checks: + * 1. If the handle is not in the active set, it's considered valid + * 2. If the handle is in the active set but has no corresponding entry in the table, + * it's considered valid (handles stale bitmap entries) + * + * This approach ensures we don't leak handles and can recover from situations where + * the bitmap contains handles that no longer have corresponding table entries. + * + * Returns: Next available XML handle counter (integer) + * Errors: Throws error when all possible handle counters are in use + */ +int +get_next_xml_handle_counter() +{ + int old_handle_counter = current_xml_handle_counter; + bool handle_valid = false; + + while (!handle_valid) + { + ++current_xml_handle_counter; + + if (current_xml_handle_counter == XML_HANDLE_COUNTER_INVALID) + { + current_xml_handle_counter = XML_HANDLE_COUNTER_START + 1; + } + + if (unlikely(current_xml_handle_counter == old_handle_counter)) + { + ereport(ERROR, + (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), + errmsg("Out of XML Handles"))); + } + + /* Check if the handle is in the active set */ + if (bms_is_member(current_xml_handle_counter, active_xml_handles_counter)) + { + /* Handle is in active set, check if it actually exists in the table */ + int document_id = 2 * current_xml_handle_counter - 1; + Relation relation = NULL; + ScanKeyData skey[1]; + SysScanDesc scan; + HeapTuple tuple; + bool entry_exists = false; + EphemeralNamedRelation enr = NULL; + + /* Only check the table if it exists using ENR lookup */ + if (xml_handle_temp_table_name != NULL) + { + enr = get_ENR(currentQueryEnv, xml_handle_temp_table_name, true); + if (enr) + { + relation = relation_open(enr->md.reliddesc, AccessShareLock); + + /* Set up scan key to look for this document_id */ + ScanKeyInit(&skey[0], + 1, + BTEqualStrategyNumber, F_INT4EQ, + Int32GetDatum(document_id)); + + /* Scan the table for this document_id */ + scan = systable_beginscan(relation, InvalidOid, false, NULL, 1, skey); + tuple = systable_getnext(scan); + + /* If we find a tuple, the entry exists */ + if (HeapTupleIsValid(tuple)) + { + entry_exists = true; + } + + systable_endscan(scan); + relation_close(relation, AccessShareLock); + } + } + /* If no entry exists in the table, we can use this handle */ + if (!entry_exists) + { + handle_valid = true; + } + /* Otherwise, continue to the next potential handle */ + } + else + { + /* Handle is not in active set, we can use it */ + handle_valid = true; + } + } + + return current_xml_handle_counter; +} + +/* Define column definitions for #xml_handle_temp_table + The table has the following structure: + * + * - document_id: A unique identifier for the XML document (INT, NOT NULL) + * - namespace_id: An identifier for the namespace, if present (INT) + * - doc_size: The size of the XML document in bytes (BIGINT) + * - ns_size: The size of the namespace in bytes (BIGINT) + * - is_namespace_null: Flag indicating if namespace is NULL (BOOLEAN) + * - xml_data: The actual XML document content (XML) + * - ns_data: The namespace content, if any (XML) + */ +static List * +create_xml_handle_columns(void) +{ + List *columns = NIL; + ColumnDef *docIdCol; + + /* Create column definitions */ + docIdCol = makeColumnDef("document_id", INT4OID, -1, InvalidOid); + docIdCol->is_not_null = true; + columns = lappend(columns, docIdCol); + columns = lappend(columns, makeColumnDef("namespace_id", INT4OID, -1, InvalidOid)); + columns = lappend(columns, makeColumnDef("doc_size", INT8OID, -1, InvalidOid)); + columns = lappend(columns, makeColumnDef("ns_size", INT8OID, -1, InvalidOid)); + columns = lappend(columns, makeColumnDef("is_namespace_null", BOOLOID, -1, InvalidOid)); + columns = lappend(columns, makeColumnDef("xml_data", XMLOID, -1, InvalidOid)); + columns = lappend(columns, makeColumnDef("ns_data", XMLOID, -1, InvalidOid)); + + return columns; +} + +/* + * generate_unique_table_name - Creates a unique table name using MD5 hash + * + * This function generates a unique table name by creating an MD5 hash of + * a base name combined with a random number. This ensures that each session + * gets a unique temp table name, avoiding conflicts when multiple sessions are + * creating these tables simultaneously. + * + * Parameters: + * base_name - The base name to use for the table + * + * Returns: + * A unique table name with the base name and an MD5 hash suffix + */ +#define MD5_HASH_LEN 32 + +static char * +generate_unique_table_name(const char *base_name) +{ + char md5[MD5_HASH_LEN + 1]; + const char *errstr = NULL; + bool success; + + /* Generate a unique input string for the MD5 hash */ + char *random_input = psprintf("%s%d", base_name, rand()); + + /* Generate MD5 hash */ + success = pg_md5_hash(random_input, strlen(random_input), md5, &errstr); + + if (unlikely(!success)) + ereport(ERROR, + (errcode(ERRCODE_INTERNAL_ERROR), + errmsg("could not compute MD5 hash: %s", errstr))); + + /* Create and return table name with prefix and MD5 hash */ + return psprintf("%s_%s", base_name, md5); +} + +/* + * create_xml_handle_temp_table: + * Creates a temporary table to store XML document handles and their associated data. + * + * This function creates a temporary table with a unique name generated using an MD5 hash + * that persists for the duration of the session. The table stores XML documents and their + * associated namespace information for use with the sp_xml_preparedocument and + * sp_xml_removedocument procedures. + * + * The unique table name helps avoid conflicts when multiple sessions are creating these + * tables simultaneously. The table name follows the pattern "#xml_handle_temp_table_[MD5 hash]". + * + * The function temporarily elevates privileges to "bbf_role_admin" to ensure it has + * the necessary permissions to create the table. It also sets the SQL dialect + * to TSQL to ensure proper table creation semantics. + */ +void +create_xml_handle_temp_table() +{ + CreateStmt *stmt = makeNode(CreateStmt); + RangeVar *relation; + Oid save_userid; + int save_sec_context; + int saved_dialect = sql_dialect; + ObjectAddress address; + QueryEnvironment *saved_queryEnv = currentQueryEnv; + MemoryContext oldContext; + char *table_name; + + /* Generate a unique table name */ + table_name = generate_unique_table_name("#xml_handle_temp_table"); + relation = makeRangeVar(NULL, table_name, -1); + + /* Switch to the top-level query environment */ + currentQueryEnv = topLevelQueryEnv; + + /* This makes it temporary table */ + relation->relpersistence = RELPERSISTENCE_TEMP; + + /* Set up the CreateStmt */ + stmt->relation = relation; + stmt->tableElts = create_xml_handle_columns(); + stmt->constraints = NIL; + stmt->inhRelations = NIL; + stmt->partspec = NULL; + stmt->ofTypename = NULL; + stmt->oncommit = ONCOMMIT_PRESERVE_ROWS; + stmt->tablespacename = NULL; + stmt->if_not_exists = false; + stmt->options = NIL; + stmt->accessMethod = NULL; + + GetUserIdAndSecContext(&save_userid, &save_sec_context); + + PG_TRY(); + { + sql_dialect = SQL_DIALECT_TSQL; + /* Create the relation (table) with the specified attributes & + * Set current user to bbf_role_admin for create permissions + */ + address = DefineRelation(stmt, RELKIND_RELATION, get_bbf_role_admin_oid(), NULL, NULL); + + /* + * Create a TOAST table for the relation if needed. + * TOAST tables store large values that don't fit in the main table pages. + * This is important for XML data which can be large. + * The second parameter (0) means no special options for the TOAST table. + */ + NewRelationCreateToastTable(address.objectId, (Datum)0); + + /* Store the table name in TopMemoryContext so it persists across transactions */ + oldContext = MemoryContextSwitchTo(TopMemoryContext); + xml_handle_temp_table_name = pstrdup(table_name); + MemoryContextSwitchTo(oldContext); + } + PG_FINALLY(); + { + SetUserIdAndSecContext(save_userid, save_sec_context); + sql_dialect = saved_dialect; + /* Restore the original query environment */ + currentQueryEnv = saved_queryEnv; + } + PG_END_TRY(); + + current_xml_handle_counter = XML_HANDLE_COUNTER_START; +} + +/* + * insert_xml_handle_entry - Stores XML document data in the temporary handle table. + * + * This function inserts a new XML document and its optional namespace data into + * the XML handle temporary table. + * The function temporarily elevates privileges to "bbf_role_admin" to ensure it has + * the necessary permissions to insert data into the table. It also sets the SQL + * dialect to TSQL to ensure proper insertion semantics. + * + * Returns: + * The document_id that can be used to reference this XML document + * + * Errors: + * Throws error if the temporary table cannot be created or accessed + */ +int +insert_xml_handle_entry(xmltype *xml_data, xmltype *ns_data, int xml_data_length, int ns_data_length) +{ + int handle_counter; + int document_id; + int namespace_id = 0; + bool is_namespace_null = true; + Relation relation; + Datum values[7]; + Oid save_userid; + int save_sec_context; + int saved_dialect = sql_dialect; + HeapTuple tuple; + bool nulls[7] = {false, true, false, true, true, false, true}; + bool table_exists = false; + EphemeralNamedRelation enr = NULL; + MemoryContext oldContext = NULL; + + /* Check if the table exists using ENR lookup */ + if (xml_handle_temp_table_name != NULL) + { + enr = get_ENR(currentQueryEnv, xml_handle_temp_table_name, true); + if (enr) + { + relation = relation_open(enr->md.reliddesc, RowExclusiveLock); + table_exists = true; + } + } + + if (!table_exists) + { + /* Table doesn't exist or was dropped, create it */ + create_xml_handle_temp_table(); + + /* Look up the newly created table */ + if (xml_handle_temp_table_name != NULL) + { + enr = get_ENR(currentQueryEnv, xml_handle_temp_table_name, true); + if (enr) + { + relation = relation_open(enr->md.reliddesc, RowExclusiveLock); + table_exists = true; + } + } + + if (!table_exists) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_TABLE), + errmsg("Failed to create XML handle temporary table"))); + } + + /* get the next handle */ + handle_counter = get_next_xml_handle_counter(); + + /* document_id is always odd and unique */ + document_id = 2 * handle_counter - 1; + + if (ns_data_length > 0) + { + /* namespace_id is always even and unique if namespace is present */ + namespace_id = 2 * handle_counter; + is_namespace_null = false; + nulls[1] = false; + nulls[3] = false; + nulls[4] = false; + nulls[6] = false; + } + + /* Set up the values for insertion */ + values[0] = Int32GetDatum(document_id); + values[1] = Int32GetDatum(namespace_id); + values[2] = Int32GetDatum(xml_data_length); + values[3] = Int32GetDatum(ns_data_length); + values[4] = BoolGetDatum(is_namespace_null); + nulls[4] = false; + + if (xml_data == NULL) + { + nulls[5] = true; + values[5] = (Datum)0; + } + else + { + values[5] = PointerGetDatum(xml_data); + } + + /* For namespace data */ + if (!nulls[6]) + { + values[6] = PointerGetDatum(ns_data); + } + else + { + values[6] = (Datum)0; + } + tuple = heap_form_tuple(RelationGetDescr(relation), values, nulls); + + GetUserIdAndSecContext(&save_userid, &save_sec_context); + sql_dialect = SQL_DIALECT_TSQL; + + PG_TRY(); + { + /* Set current user to bbf_role_admin for insert permissions */ + SetUserIdAndSecContext(get_bbf_role_admin_oid(), save_sec_context | SECURITY_LOCAL_USERID_CHANGE); + + /* Insert the entries into the table */ + simple_heap_insert(relation, tuple); + CommandCounterIncrement(); + + /* + * Switch to TopMemoryContext to ensure the bitmap set persists across transactions. + * This prevents the bitmap set from being freed when the current memory context + * is reset, which would cause the handles to be lost and potentially reused. + */ + oldContext = MemoryContextSwitchTo(TopMemoryContext); + active_xml_handles_counter = bms_add_member(active_xml_handles_counter, current_xml_handle_counter); + MemoryContextSwitchTo(oldContext); + } + PG_FINALLY(); + { + SetUserIdAndSecContext(save_userid, save_sec_context); + sql_dialect = saved_dialect; + } + PG_END_TRY(); + + heap_freetuple(tuple); + + relation_close(relation, NoLock); + + return document_id; +} + +/* + * delete_xml_handle_entry - Removes an XML document from the xml handle temp table. + * + * This function deletes an XML document entry from the temporary handle table + * based on its document_id. It also releases the associated handle by removing + * it from the active_xml_handles bitmap set, making the handle available for + * reuse. This is typically called by sp_xml_removedocument to clean up XML + * documents when they are no longer needed. + * + * The function temporarily elevates privileges to "bbf_role_admin" to ensure it has + * the necessary permissions to delete data from the table. It also sets the SQL + * dialect to TSQL to ensure proper deletion semantics. + */ +void +delete_xml_handle_entry(int document_id) +{ + Relation relation; + ScanKeyData skey[1]; + SysScanDesc scan; + HeapTuple tuple; + bool found = false; + int curr_handle_counter; + int save_sec_context; + Oid save_userid; + int saved_dialect = sql_dialect; + MemoryContext oldContext = NULL; + bool table_exists = false; + EphemeralNamedRelation enr = NULL; + + /* Check for negative document ID */ + if (document_id <= 0) + { + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("Could not find prepared statement with handle %d", document_id))); + } + + /* Calculate the handle counter */ + curr_handle_counter = (document_id + 1) / 2; + + /* Check if the handle is still active */ + if (!bms_is_member(curr_handle_counter, active_xml_handles_counter)) + { + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("Could not find prepared statement with handle %d", document_id))); + } + + /* Check if the table exists using ENR lookup by name */ + if (xml_handle_temp_table_name != NULL) + { + enr = get_ENR(currentQueryEnv, xml_handle_temp_table_name, true); + if (enr) + { + relation = relation_open(enr->md.reliddesc, RowExclusiveLock); + table_exists = true; + } + } + + if (!table_exists) + { + /* Table doesn't exist, so the handle definitely doesn't exist */ + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("Could not find prepared statement with handle %d", document_id))); + } + + ScanKeyInit(&skey[0], + 1, + BTEqualStrategyNumber, F_INT4EQ, + Int32GetDatum(document_id)); + + + scan = systable_beginscan(relation, InvalidOid, false, NULL, 1, skey); + tuple = systable_getnext(scan); + + /* Find and delete the tuple */ + if (HeapTupleIsValid(tuple)) + { + GetUserIdAndSecContext(&save_userid, &save_sec_context); + sql_dialect = SQL_DIALECT_TSQL; + + PG_TRY(); + { + /* Set current user to bbf_role_admin for delete permissions */ + SetUserIdAndSecContext(get_bbf_role_admin_oid(), save_sec_context | SECURITY_LOCAL_USERID_CHANGE); + simple_heap_delete(relation, &tuple->t_self); + CommandCounterIncrement(); + oldContext = MemoryContextSwitchTo(TopMemoryContext); + active_xml_handles_counter = bms_del_member(active_xml_handles_counter, curr_handle_counter); + MemoryContextSwitchTo(oldContext); + } + PG_FINALLY(); + { + SetUserIdAndSecContext(save_userid, save_sec_context); + sql_dialect = saved_dialect; + } + PG_END_TRY(); + + found = true; + } + + systable_endscan(scan); + relation_close(relation, NoLock); + + /* If we didn't find the handle or couldn't delete it, throw an error */ + if (!found) + { + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("Could not find prepared statement with handle %d", document_id))); + } +} + +/* + * reset_cached_xml_handle: + * Cleans up all the stale states and resets the xml handles. + * This function should be called when a connection is reset or terminated. + */ +void +reset_cached_xml_handle() +{ + /* Reset active handles bitmap */ + bms_free(active_xml_handles_counter); + active_xml_handles_counter = NULL; + + /* Reset xml handles */ + current_xml_handle_counter = XML_HANDLE_COUNTER_INVALID; + + /* Reset the table name */ + xml_handle_temp_table_name = NULL; +} + +Datum +sp_xml_preparedocument(PG_FUNCTION_ARGS) +{ + char *xml_text = PG_ARGISNULL(1) ? NULL : text_to_cstring(PG_GETARG_TEXT_PP(1)); + char *xpath_namespaces = PG_ARGISNULL(2) ? NULL : text_to_cstring(PG_GETARG_TEXT_PP(2)); + bool is_xml_text_well_formed; + bool is_xpath_namespaces_well_formed; + xmltype *xml_data; + xmltype *ns_data; + int document_id; + int xml_data_length = xml_text == NULL ? 0 : strlen(xml_text); + int ns_data_length = xpath_namespaces == NULL ? 0 : strlen(xpath_namespaces); + + HeapTuple tuple; + HeapTupleHeader result; + TupleDesc tupdesc; + bool isnull = false; + Datum values[1]; + + /* Validating the given xml text string & Handle NULL case */ + if (xml_data_length == 0) + { + xml_data = NULL; + } + else + { + is_xml_text_well_formed = DatumGetBool(DirectFunctionCall1(xml_is_well_formed_document, PG_GETARG_DATUM(1))); + + if (is_xml_text_well_formed) + { + xml_data = (xmltype *) PG_GETARG_DATUM(1); + } + else + { + ereport(ERROR, + (errcode(ERRCODE_INVALID_XML_DOCUMENT), + errmsg("The XML input is not well-formed."))); + } + } + + /* Validating the given namespaces & Handle NULL case */ + if (ns_data_length == 0) + { + ns_data = NULL; + } + else + { + is_xpath_namespaces_well_formed = DatumGetBool(DirectFunctionCall1(xml_is_well_formed_document, PG_GETARG_DATUM(2))); + + if (is_xpath_namespaces_well_formed) + { + ns_data = (xmltype *) PG_GETARG_DATUM(2); + } + else + { + ereport(ERROR, + (errcode(ERRCODE_INVALID_XML_DOCUMENT), + errmsg("The XPath namespace declarations are not well-formed."))); + } + } + + /* Insert the entries into temporary table and return the document_id */ + document_id = insert_xml_handle_entry(xml_data, ns_data, xml_data_length, ns_data_length); + + /* Return back the handle */ + tupdesc = CreateTemplateTupleDesc(1); + TupleDescInitEntry(tupdesc, (AttrNumber) 1, "document_id", INT4OID, -1, 0); + tupdesc = BlessTupleDesc(tupdesc); + values[0] = Int32GetDatum(document_id); + tuple = heap_form_tuple(tupdesc, values, &isnull); + + result = (HeapTupleHeader) palloc(tuple->t_len); + memcpy(result, tuple->t_data, tuple->t_len); + + heap_freetuple(tuple); + ReleaseTupleDesc(tupdesc); + + PG_RETURN_HEAPTUPLEHEADER(result); +} + +Datum +sp_xml_removedocument(PG_FUNCTION_ARGS) +{ + int doc_handle; + + /* Check if document handle argument is NULL */ + if (PG_ARGISNULL(0)) + { + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("Could not find prepared statement with handle NULL"))); + } + + /* Get the document handle */ + doc_handle = PG_GETARG_INT32(0); + + /* Remove the entry from the temporary table */ + delete_xml_handle_entry(doc_handle); + + PG_RETURN_VOID(); +} \ No newline at end of file diff --git a/contrib/babelfishpg_tsql/src/session.c b/contrib/babelfishpg_tsql/src/session.c index 06a3fd647de..7c097729072 100644 --- a/contrib/babelfishpg_tsql/src/session.c +++ b/contrib/babelfishpg_tsql/src/session.c @@ -244,6 +244,7 @@ reset_session_properties(void) { reset_cached_batch(); reset_cached_cursor(); + reset_cached_xml_handle(); pltsql_explain_only = false; pltsql_explain_analyze = false; } diff --git a/test/JDBC/expected/sp_xml_preparedocument-vu-cleanup.out b/test/JDBC/expected/sp_xml_preparedocument-vu-cleanup.out new file mode 100644 index 00000000000..8de3e973e0e --- /dev/null +++ b/test/JDBC/expected/sp_xml_preparedocument-vu-cleanup.out @@ -0,0 +1,11 @@ +DROP TABLE sp_xml_preparedocument_HandleStore; +GO + +DROP DATABASE sp_xml_preparedocument_temp_db; +GO + +DROP TABLE handle_store; +GO + +DROP PROCEDURE test_xml_proc; +GO diff --git a/test/JDBC/expected/sp_xml_preparedocument-vu-prepare.out b/test/JDBC/expected/sp_xml_preparedocument-vu-prepare.out new file mode 100644 index 00000000000..38b6f584fbc --- /dev/null +++ b/test/JDBC/expected/sp_xml_preparedocument-vu-prepare.out @@ -0,0 +1,17 @@ +CREATE TABLE sp_xml_preparedocument_HandleStore (handle_value int); +GO + +CREATE DATABASE sp_xml_preparedocument_temp_db; +GO + +CREATE TABLE handle_store(handle_id INT); +GO + +CREATE PROCEDURE test_xml_proc +AS +BEGIN +DECLARE @hdoc INT; +EXEC sp_xml_preparedocument @hdoc OUTPUT, 'proc_value'; +SELECT @hdoc AS handle_inside_proc; +END +GO diff --git a/test/JDBC/expected/sp_xml_preparedocument-vu-verify.out b/test/JDBC/expected/sp_xml_preparedocument-vu-verify.out new file mode 100644 index 00000000000..b3461b6d790 --- /dev/null +++ b/test/JDBC/expected/sp_xml_preparedocument-vu-verify.out @@ -0,0 +1,495 @@ + +-- QUERIES for different test cases for sp_xml_preparedocument and sp_xml_removedocument procedure +-- When 1st (xmltext) and 2nd (xpath namespaces) parameters are not given +DECLARE @hdoc INT; +EXEC sp_xml_preparedocument @hdoc OUTPUT; +SELECT @hdoc as handle; +EXEC sp_xml_removedocument @hdoc; +GO +~~START~~ +int +1 +~~END~~ + + +-- When xmltext is NULL and namespace is not given +DECLARE @hdoc INT; +EXEC sp_xml_preparedocument @hdoc OUTPUT, NULL; +SELECT @hdoc as handle; +EXEC sp_xml_removedocument @hdoc; +GO +~~START~~ +int +3 +~~END~~ + + +-- When xmltext is a valid xml and namespace is not given +DECLARE @hdoc INT; +EXEC sp_xml_preparedocument @hdoc OUTPUT, 'value'; +SELECT @hdoc as handle; +EXEC sp_xml_removedocument @hdoc; +GO +~~START~~ +int +5 +~~END~~ + + +-- When xmltext is invalid and namespaces is not given +DECLARE @hdoc INT; +EXEC sp_xml_preparedocument @hdoc OUTPUT, 'value', ''; +SELECT @hdoc as handle; +EXEC sp_xml_removedocument @hdoc; +GO +~~START~~ +int +7 +~~END~~ + + +-- When xmltext and namespaces both are given (invalid) +DECLARE @hdoc INT; +EXEC sp_xml_preparedocument @hdoc OUTPUT, ''; +SELECT @hdoc as handle; +EXEC sp_xml_removedocument @hdoc; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The XML input is not well-formed.)~~ + + +-- When xmltext is valid but namespace invalid +DECLARE @hdoc INT; +EXEC sp_xml_preparedocument @hdoc OUTPUT, 'value', 'xmlns:ns1="http://example.com/ns1"/>'; +SELECT @hdoc as handle; +EXEC sp_xml_removedocument @hdoc; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The XPath namespace declarations are not well-formed.)~~ + + +--When xmltext is invalid but namespace valid +DECLARE @hdoc INT; +EXEC sp_xml_preparedocument @hdoc OUTPUT, ''; +SELECT @hdoc as handle; +EXEC sp_xml_removedocument @hdoc; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The XML input is not well-formed.)~~ + + +-- When xmltext is NULL and valid namespace +DECLARE @hdoc INT; +EXEC sp_xml_preparedocument @hdoc OUTPUT, NULL, ''; +SELECT @hdoc as handle; +EXEC sp_xml_removedocument @hdoc; +GO +~~START~~ +int +9 +~~END~~ + + +-- When xmltext is NULL and invalid namespace +DECLARE @hdoc INT; +EXEC sp_xml_preparedocument @hdoc OUTPUT, NULL, 'xmlns:ns1="http://example.com/ns1"/>'; +SELECT @hdoc as handle; +EXEC sp_xml_removedocument @hdoc; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The XPath namespace declarations are not well-formed.)~~ + + +-- When empty xml text is given +DECLARE @hdoc INT; +EXEC sp_xml_preparedocument @hdoc OUTPUT,'', ''; +SELECT @hdoc as handle; +EXEC sp_xml_removedocument @hdoc; +GO +~~START~~ +int +11 +~~END~~ + + +-- When empty namespace is given +DECLARE @hdoc INT; +EXEC sp_xml_preparedocument @hdoc OUTPUT, 'value', ''; +SELECT @hdoc as handle; +EXEC sp_xml_removedocument @hdoc; +GO +~~START~~ +int +13 +~~END~~ + + +-- When both xmltext and namespace are empty +DECLARE @hdoc INT; +EXEC sp_xml_preparedocument @hdoc OUTPUT,'', ''; +SELECT @hdoc as handle; +EXEC sp_xml_removedocument @hdoc; +GO +~~START~~ +int +15 +~~END~~ + + +-- When large handle is given +DECLARE @hdoc INT; +DECLARE @counter BIGINT = 1; +WHILE @counter <= 2000 +BEGIN +EXEC sp_xml_preparedocument @hdoc OUTPUT; +SET @counter = @counter + 1; +END; +SELECT @hdoc as handle; +GO +~~START~~ +int +4015 +~~END~~ + + +--When database is changed in the session +SELECT db_name() as current_database; +GO +~~START~~ +nvarchar +master +~~END~~ + + +DECLARE @handle1 int; +EXEC sp_xml_preparedocument @handle1 OUTPUT, 'data'; +SELECT @handle1 as 'Current Handle'; +INSERT INTO sp_xml_preparedocument_HandleStore (handle_value) VALUES (@handle1); +GO +~~START~~ +int +4017 +~~END~~ + +~~ROW COUNT: 1~~ + + +USE sp_xml_preparedocument_temp_db; +GO + +DECLARE @handle2 int; +SELECT @handle2 = handle_value FROM master.dbo.sp_xml_preparedocument_HandleStore; +SELECT @handle2 as 'Retrieved Handle'; +BEGIN TRY + EXEC sp_xml_removedocument @handle2; + PRINT 'Document successfully removed using handle from previous database'; +END TRY +BEGIN CATCH + PRINT 'Error' ; +END CATCH; +GO +~~START~~ +int +4017 +~~END~~ + + +USE master +GO + + +-- Variable declaration and initialisation +DECLARE @hdoc INT; +DECLARE @xml_text varchar(100) = ''; +DECLARE @xpath_namespaces varchar(100) = ''; +EXEC sp_xml_preparedocument @hdoc OUTPUT, @xml_text, @xpath_namespaces; +SELECT @hdoc as handle; +EXEC sp_xml_removedocument @hdoc; +GO +~~START~~ +int +4019 +~~END~~ + + +--For complex xml texts 1 +DECLARE @hdoc INT; +EXEC sp_xml_preparedocument @hdoc OUTPUT, +' + + IT + + + John Doe + Developer + + SQL + Java + + + + +'; +SELECT @hdoc as handle; +EXEC sp_xml_removedocument @hdoc; +GO +~~START~~ +int +4021 +~~END~~ + + +-- For complex xml text2 +DECLARE @hdoc INT; +DECLARE @doc VARCHAR(1000); +SET @doc = ' + + + + + + + + + + + + +'; +EXEC sp_xml_preparedocument @hdoc OUTPUT, @doc; +SELECT @hdoc as handle; +EXEC sp_xml_removedocument @hdoc; +GO +~~START~~ +int +4023 +~~END~~ + + +-- For complex namespaces +DECLARE @hdoc INT; +EXEC sp_xml_preparedocument @hdoc OUTPUT, '', +' + + + value + + +'; +SELECT @hdoc as handle; +EXEC sp_xml_removedocument @hdoc; +GO +~~START~~ +int +4025 +~~END~~ + + +--When given xml text length is too large (above max limit) +DECLARE @hdoc int; +DECLARE @xml_text varchar(max) = '' + repeat('', 200000000) + ''; +EXEC sp_xml_preparedocument @hdoc output, @xml_text; +SELECT @hdoc as handle; +EXEC sp_xml_removedocument @hdoc; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: requested length too large)~~ + + +-- When namespace length is too large (above max limit) +DECLARE @hdoc int; +DECLARE @namespace_text varchar(max) = ''; +EXEC sp_xml_preparedocument @hdoc output, NULL, @namespace_text; +SELECT @hdoc as handle; +EXEC sp_xml_removedocument @hdoc; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: requested length too large)~~ + + +--Test with parameter by name syntax 1 +DECLARE @z int; +EXEC sp_xml_preparedocument @hdoc = @z OUTPUT, @xmltext = 'value', @xpath_namespaces = ''; +SELECT @z as handle; +EXEC sp_xml_removedocument @z; +GO +~~START~~ +int +4027 +~~END~~ + + +--Test with parameter by name syntax 2 +DECLARE @z int; +DECLARE @hdoc int; +EXEC sp_xml_preparedocument @hdoc OUTPUT, + @xmltext = 'value', + @xpath_namespaces = ''; +SELECT @hdoc as handle; +EXEC sp_xml_removedocument @hdoc; +GO +~~START~~ +int +4029 +~~END~~ + + +-- Double quoted string +DECLARE @hdoc INT; +EXEC sp_xml_preparedocument @hdoc OUTPUT, "value"; +SELECT @hdoc as handle; +EXEC sp_xml_removedocument @hdoc; +GO +~~START~~ +int +4031 +~~END~~ + + +-- Impact of rollback on prepared handle +BEGIN TRANSACTION; +DECLARE @hdoc INT; +EXEC sp_xml_preparedocument @hdoc OUTPUT, 'rollback_test'; +SELECT @hdoc AS handle_before_rollback; +ROLLBACK TRANSACTION; +-- Handle will be invalid after rollback +EXEC sp_xml_removedocument @hdoc; +GO +~~START~~ +int +4033 +~~END~~ + +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Could not find prepared statement with handle 4033)~~ + + +-- Impact of statement terminating/transaction abort errors +BEGIN TRANSACTION; +DECLARE @hdoc INT; +EXEC sp_xml_preparedocument @hdoc OUTPUT, 'txn_value'; +SELECT @hdoc AS handle_before_error; +GO +~~START~~ +int +4035 +~~END~~ + +-- This will cause an error and abort the transaction +SELECT FROM; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: syntax error near 'FROM' at line 2 and character position 7)~~ + + +-- Verify handle still works or not +DECLARE @hdoc INT; +EXEC sp_xml_preparedocument @hdoc OUTPUT, 'txn_value'; +SELECT @hdoc AS handle_after_error; +-- calculating handle_before_error and that should not exist +DECLARE @stored_hdoc INT = @hdoc - 2; +EXEC sp_xml_removedocument @stored_hdoc; +GO +~~START~~ +int +4037 +~~END~~ + +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Could not find prepared statement with handle 4035)~~ + + +-- Test with large XML documents +DECLARE @hdoc int; +DECLARE @xml_text varchar(max) = '' + repeat('', 20000) + ''; +EXEC sp_xml_preparedocument @hdoc output, @xml_text; +SELECT @hdoc as handle; +EXEC sp_xml_removedocument @hdoc; +GO +~~START~~ +int +4039 +~~END~~ + + +-- Test with very large XML documents +DECLARE @hdoc int; +DECLARE @xml_text varchar(max) = '' + repeat('', 200000) + ''; +EXEC sp_xml_preparedocument @hdoc output, @xml_text; +SELECT @hdoc as handle; +EXEC sp_xml_removedocument @hdoc; +GO +~~START~~ +int +4041 +~~END~~ + + +-- impact of reset connection +DECLARE @hdoc INT; +EXEC sp_xml_preparedocument @hdoc OUTPUT, 'value'; +SELECT @hdoc as handle; +INSERT INTO handle_store VALUES (@hdoc); +-- This resets the connection +EXEC sys.sp_reset_connection; +GO +~~START~~ +int +4043 +~~END~~ + +~~ROW COUNT: 1~~ + +-- Handle will be invalid after reset +DECLARE @stored_hdoc INT; +SELECT @stored_hdoc = handle_id FROM handle_store; +EXEC sp_xml_removedocument @stored_hdoc; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Could not find prepared statement with handle 4043)~~ + + +-- Now handles will start from 1 +DECLARE @hdoc INT; +EXEC sp_xml_preparedocument @hdoc OUTPUT, 'value'; +SELECT @hdoc as handle; +GO +~~START~~ +int +1 +~~END~~ + + +-- Prepare/drop XML inside procedure +-- Execute procedure and verify handle +EXEC test_xml_proc; +GO +~~START~~ +int +3 +~~END~~ + diff --git a/test/JDBC/expected/sp_xml_removedocument-vu-verify.out b/test/JDBC/expected/sp_xml_removedocument-vu-verify.out new file mode 100644 index 00000000000..dd72e750a20 --- /dev/null +++ b/test/JDBC/expected/sp_xml_removedocument-vu-verify.out @@ -0,0 +1,38 @@ +-- QUERIES for different test cases for sp_xml_preparedocument and sp_xml_removedocument procedure +-- creating a handle and then removing it, 2ND execution of this will throw an error as the handle is removed by first remove procedure +DECLARE @hdoc INT; +EXEC sp_xml_preparedocument @hdoc OUTPUT, 'value', ''; +EXEC sp_xml_removedocument @hdoc; +EXEC sp_xml_removedocument @hdoc; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Could not find prepared statement with handle 1)~~ + + +-- Removing negative handle +DECLARE @hdoc INT= -1; +EXEC sp_xml_removedocument @hdoc; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Could not find prepared statement with handle -1)~~ + + +-- Removing a handle which does not exists in the session +DECLARE @hdoc INT=999999; +EXEC sp_xml_removedocument @hdoc; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Could not find prepared statement with handle 999999)~~ + + +-- Removing a handle which is NULL; +DECLARE @hdoc INT=null; +EXEC sp_xml_removedocument @hdoc; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Could not find prepared statement with handle NULL)~~ + diff --git a/test/JDBC/input/xml/sp_xml_preparedocument-vu-cleanup.sql b/test/JDBC/input/xml/sp_xml_preparedocument-vu-cleanup.sql new file mode 100644 index 00000000000..8de3e973e0e --- /dev/null +++ b/test/JDBC/input/xml/sp_xml_preparedocument-vu-cleanup.sql @@ -0,0 +1,11 @@ +DROP TABLE sp_xml_preparedocument_HandleStore; +GO + +DROP DATABASE sp_xml_preparedocument_temp_db; +GO + +DROP TABLE handle_store; +GO + +DROP PROCEDURE test_xml_proc; +GO diff --git a/test/JDBC/input/xml/sp_xml_preparedocument-vu-prepare.sql b/test/JDBC/input/xml/sp_xml_preparedocument-vu-prepare.sql new file mode 100644 index 00000000000..38b6f584fbc --- /dev/null +++ b/test/JDBC/input/xml/sp_xml_preparedocument-vu-prepare.sql @@ -0,0 +1,17 @@ +CREATE TABLE sp_xml_preparedocument_HandleStore (handle_value int); +GO + +CREATE DATABASE sp_xml_preparedocument_temp_db; +GO + +CREATE TABLE handle_store(handle_id INT); +GO + +CREATE PROCEDURE test_xml_proc +AS +BEGIN +DECLARE @hdoc INT; +EXEC sp_xml_preparedocument @hdoc OUTPUT, 'proc_value'; +SELECT @hdoc AS handle_inside_proc; +END +GO diff --git a/test/JDBC/input/xml/sp_xml_preparedocument-vu-verify.sql b/test/JDBC/input/xml/sp_xml_preparedocument-vu-verify.sql new file mode 100644 index 00000000000..d7c45171634 --- /dev/null +++ b/test/JDBC/input/xml/sp_xml_preparedocument-vu-verify.sql @@ -0,0 +1,312 @@ + +-- QUERIES for different test cases for sp_xml_preparedocument and sp_xml_removedocument procedure +-- When 1st (xmltext) and 2nd (xpath namespaces) parameters are not given +DECLARE @hdoc INT; +EXEC sp_xml_preparedocument @hdoc OUTPUT; +SELECT @hdoc as handle; +EXEC sp_xml_removedocument @hdoc; +GO + +-- When xmltext is NULL and namespace is not given +DECLARE @hdoc INT; +EXEC sp_xml_preparedocument @hdoc OUTPUT, NULL; +SELECT @hdoc as handle; +EXEC sp_xml_removedocument @hdoc; +GO + +-- When xmltext is a valid xml and namespace is not given +DECLARE @hdoc INT; +EXEC sp_xml_preparedocument @hdoc OUTPUT, 'value'; +SELECT @hdoc as handle; +EXEC sp_xml_removedocument @hdoc; +GO + +-- When xmltext is invalid and namespaces is not given +DECLARE @hdoc INT; +EXEC sp_xml_preparedocument @hdoc OUTPUT, 'value', ''; +SELECT @hdoc as handle; +EXEC sp_xml_removedocument @hdoc; +GO + +-- When xmltext and namespaces both are given (invalid) +DECLARE @hdoc INT; +EXEC sp_xml_preparedocument @hdoc OUTPUT, ''; +SELECT @hdoc as handle; +EXEC sp_xml_removedocument @hdoc; +GO + +-- When xmltext is valid but namespace invalid +DECLARE @hdoc INT; +EXEC sp_xml_preparedocument @hdoc OUTPUT, 'value', 'xmlns:ns1="http://example.com/ns1"/>'; +SELECT @hdoc as handle; +EXEC sp_xml_removedocument @hdoc; +GO + +--When xmltext is invalid but namespace valid +DECLARE @hdoc INT; +EXEC sp_xml_preparedocument @hdoc OUTPUT, ''; +SELECT @hdoc as handle; +EXEC sp_xml_removedocument @hdoc; +GO + +-- When xmltext is NULL and valid namespace +DECLARE @hdoc INT; +EXEC sp_xml_preparedocument @hdoc OUTPUT, NULL, ''; +SELECT @hdoc as handle; +EXEC sp_xml_removedocument @hdoc; +GO + +-- When xmltext is NULL and invalid namespace +DECLARE @hdoc INT; +EXEC sp_xml_preparedocument @hdoc OUTPUT, NULL, 'xmlns:ns1="http://example.com/ns1"/>'; +SELECT @hdoc as handle; +EXEC sp_xml_removedocument @hdoc; +GO + +-- When empty xml text is given +DECLARE @hdoc INT; +EXEC sp_xml_preparedocument @hdoc OUTPUT,'', ''; +SELECT @hdoc as handle; +EXEC sp_xml_removedocument @hdoc; +GO + +-- When empty namespace is given +DECLARE @hdoc INT; +EXEC sp_xml_preparedocument @hdoc OUTPUT, 'value', ''; +SELECT @hdoc as handle; +EXEC sp_xml_removedocument @hdoc; +GO + +-- When both xmltext and namespace are empty +DECLARE @hdoc INT; +EXEC sp_xml_preparedocument @hdoc OUTPUT,'', ''; +SELECT @hdoc as handle; +EXEC sp_xml_removedocument @hdoc; +GO + +-- When large handle is given +DECLARE @hdoc INT; +DECLARE @counter BIGINT = 1; +WHILE @counter <= 2000 +BEGIN +EXEC sp_xml_preparedocument @hdoc OUTPUT; +SET @counter = @counter + 1; +END; +SELECT @hdoc as handle; +GO + +--When database is changed in the session +SELECT db_name() as current_database; +GO + +DECLARE @handle1 int; +EXEC sp_xml_preparedocument @handle1 OUTPUT, 'data'; +SELECT @handle1 as 'Current Handle'; +INSERT INTO sp_xml_preparedocument_HandleStore (handle_value) VALUES (@handle1); +GO + +USE sp_xml_preparedocument_temp_db; +GO + +DECLARE @handle2 int; +SELECT @handle2 = handle_value FROM master.dbo.sp_xml_preparedocument_HandleStore; +SELECT @handle2 as 'Retrieved Handle'; +BEGIN TRY + EXEC sp_xml_removedocument @handle2; + PRINT 'Document successfully removed using handle from previous database'; +END TRY +BEGIN CATCH + PRINT 'Error' ; +END CATCH; +GO + +USE master +GO + + +-- Variable declaration and initialisation +DECLARE @hdoc INT; +DECLARE @xml_text varchar(100) = ''; +DECLARE @xpath_namespaces varchar(100) = ''; +EXEC sp_xml_preparedocument @hdoc OUTPUT, @xml_text, @xpath_namespaces; +SELECT @hdoc as handle; +EXEC sp_xml_removedocument @hdoc; +GO + +--For complex xml texts 1 +DECLARE @hdoc INT; +EXEC sp_xml_preparedocument @hdoc OUTPUT, +' + + IT + + + John Doe + Developer + + SQL + Java + + + + +'; +SELECT @hdoc as handle; +EXEC sp_xml_removedocument @hdoc; +GO + +-- For complex xml text2 +DECLARE @hdoc INT; +DECLARE @doc VARCHAR(1000); +SET @doc = ' + + + + + + + + + + + + +'; +EXEC sp_xml_preparedocument @hdoc OUTPUT, @doc; +SELECT @hdoc as handle; +EXEC sp_xml_removedocument @hdoc; +GO + +-- For complex namespaces +DECLARE @hdoc INT; +EXEC sp_xml_preparedocument @hdoc OUTPUT, '', +' + + + value + + +'; +SELECT @hdoc as handle; +EXEC sp_xml_removedocument @hdoc; +GO + +--When given xml text length is too large (above max limit) +DECLARE @hdoc int; +DECLARE @xml_text varchar(max) = '' + repeat('', 200000000) + ''; +EXEC sp_xml_preparedocument @hdoc output, @xml_text; +SELECT @hdoc as handle; +EXEC sp_xml_removedocument @hdoc; +GO + +-- When namespace length is too large (above max limit) +DECLARE @hdoc int; +DECLARE @namespace_text varchar(max) = ''; +EXEC sp_xml_preparedocument @hdoc output, NULL, @namespace_text; +SELECT @hdoc as handle; +EXEC sp_xml_removedocument @hdoc; +GO + +--Test with parameter by name syntax 1 +DECLARE @z int; +EXEC sp_xml_preparedocument @hdoc = @z OUTPUT, @xmltext = 'value', @xpath_namespaces = ''; +SELECT @z as handle; +EXEC sp_xml_removedocument @z; +GO + +--Test with parameter by name syntax 2 +DECLARE @z int; +DECLARE @hdoc int; +EXEC sp_xml_preparedocument @hdoc OUTPUT, + @xmltext = 'value', + @xpath_namespaces = ''; +SELECT @hdoc as handle; +EXEC sp_xml_removedocument @hdoc; +GO + +-- Double quoted string +DECLARE @hdoc INT; +EXEC sp_xml_preparedocument @hdoc OUTPUT, "value"; +SELECT @hdoc as handle; +EXEC sp_xml_removedocument @hdoc; +GO + +-- Impact of rollback on prepared handle +BEGIN TRANSACTION; +DECLARE @hdoc INT; +EXEC sp_xml_preparedocument @hdoc OUTPUT, 'rollback_test'; +SELECT @hdoc AS handle_before_rollback; +ROLLBACK TRANSACTION; +-- Handle will be invalid after rollback +EXEC sp_xml_removedocument @hdoc; +GO + +-- Impact of statement terminating/transaction abort errors +BEGIN TRANSACTION; +DECLARE @hdoc INT; +EXEC sp_xml_preparedocument @hdoc OUTPUT, 'txn_value'; +SELECT @hdoc AS handle_before_error; +GO +-- This will cause an error and abort the transaction +SELECT FROM; +GO + +-- Verify handle still works or not +DECLARE @hdoc INT; +EXEC sp_xml_preparedocument @hdoc OUTPUT, 'txn_value'; +SELECT @hdoc AS handle_after_error; +-- calculating handle_before_error and that should not exist +DECLARE @stored_hdoc INT = @hdoc - 2; +EXEC sp_xml_removedocument @stored_hdoc; +GO + +-- Test with large XML documents +DECLARE @hdoc int; +DECLARE @xml_text varchar(max) = '' + repeat('', 20000) + ''; +EXEC sp_xml_preparedocument @hdoc output, @xml_text; +SELECT @hdoc as handle; +EXEC sp_xml_removedocument @hdoc; +GO + +-- Test with very large XML documents +DECLARE @hdoc int; +DECLARE @xml_text varchar(max) = '' + repeat('', 200000) + ''; +EXEC sp_xml_preparedocument @hdoc output, @xml_text; +SELECT @hdoc as handle; +EXEC sp_xml_removedocument @hdoc; +GO + +-- impact of reset connection +DECLARE @hdoc INT; +EXEC sp_xml_preparedocument @hdoc OUTPUT, 'value'; +SELECT @hdoc as handle; +INSERT INTO handle_store VALUES (@hdoc); +-- This resets the connection +EXEC sys.sp_reset_connection; +GO +-- Handle will be invalid after reset +DECLARE @stored_hdoc INT; +SELECT @stored_hdoc = handle_id FROM handle_store; +EXEC sp_xml_removedocument @stored_hdoc; +GO + +-- Now handles will start from 1 +DECLARE @hdoc INT; +EXEC sp_xml_preparedocument @hdoc OUTPUT, 'value'; +SELECT @hdoc as handle; +GO + +-- Prepare/drop XML inside procedure +-- Execute procedure and verify handle +EXEC test_xml_proc; +GO diff --git a/test/JDBC/input/xml/sp_xml_removedocument-vu-verify.sql b/test/JDBC/input/xml/sp_xml_removedocument-vu-verify.sql new file mode 100644 index 00000000000..9cb82662201 --- /dev/null +++ b/test/JDBC/input/xml/sp_xml_removedocument-vu-verify.sql @@ -0,0 +1,22 @@ +-- QUERIES for different test cases for sp_xml_preparedocument and sp_xml_removedocument procedure +-- creating a handle and then removing it, 2ND execution of this will throw an error as the handle is removed by first remove procedure +DECLARE @hdoc INT; +EXEC sp_xml_preparedocument @hdoc OUTPUT, 'value', ''; +EXEC sp_xml_removedocument @hdoc; +EXEC sp_xml_removedocument @hdoc; +GO + +-- Removing negative handle +DECLARE @hdoc INT= -1; +EXEC sp_xml_removedocument @hdoc; +GO + +-- Removing a handle which does not exists in the session +DECLARE @hdoc INT=999999; +EXEC sp_xml_removedocument @hdoc; +GO + +-- Removing a handle which is NULL; +DECLARE @hdoc INT=null; +EXEC sp_xml_removedocument @hdoc; +GO \ No newline at end of file diff --git a/test/JDBC/upgrade/13_4/schedule b/test/JDBC/upgrade/13_4/schedule index 05e6a3bc479..fa84cfebc4c 100644 --- a/test/JDBC/upgrade/13_4/schedule +++ b/test/JDBC/upgrade/13_4/schedule @@ -260,6 +260,8 @@ test_conv_string_to_smalldatetime-before-14_6 test_conv_string_to_time-before-13_6 BABEL-5031 test_conv_money_to_varchar +sp_xml_preparedocument +sp_xml_removedocument fixeddecimal_modulo BABEL-NUMERIC_EXPR test_conv_float_to_varchar_char_before_17_4 diff --git a/test/JDBC/upgrade/13_5/schedule b/test/JDBC/upgrade/13_5/schedule index a0fbae8f133..4f60f099a9d 100644 --- a/test/JDBC/upgrade/13_5/schedule +++ b/test/JDBC/upgrade/13_5/schedule @@ -313,6 +313,8 @@ test_conv_string_to_smalldatetime-before-14_6 test_conv_string_to_time-before-13_6 BABEL-5031 test_conv_money_to_varchar +sp_xml_preparedocument +sp_xml_removedocument fixeddecimal_modulo BABEL-NUMERIC_EXPR test_conv_float_to_varchar_char_before_17_4 diff --git a/test/JDBC/upgrade/13_6/schedule b/test/JDBC/upgrade/13_6/schedule index c553647bf2a..88be1f34cec 100644 --- a/test/JDBC/upgrade/13_6/schedule +++ b/test/JDBC/upgrade/13_6/schedule @@ -370,6 +370,8 @@ test_conv_string_to_smalldatetime-before-14_6 test_conv_string_to_time-before-17_4 BABEL-5031 test_conv_money_to_varchar +sp_xml_preparedocument +sp_xml_removedocument fixeddecimal_modulo BABEL-NUMERIC_EXPR test_conv_float_to_varchar_char_before_17_4 diff --git a/test/JDBC/upgrade/13_7/schedule b/test/JDBC/upgrade/13_7/schedule index 4ca88da321a..e13039d836f 100644 --- a/test/JDBC/upgrade/13_7/schedule +++ b/test/JDBC/upgrade/13_7/schedule @@ -363,6 +363,8 @@ test_conv_string_to_smalldatetime-before-14_6 test_conv_string_to_time-before-17_4 BABEL-5031 test_conv_money_to_varchar +sp_xml_preparedocument +sp_xml_removedocument fixeddecimal_modulo BABEL-NUMERIC_EXPR test_conv_float_to_varchar_char_before_17_4 diff --git a/test/JDBC/upgrade/13_8/schedule b/test/JDBC/upgrade/13_8/schedule index 4ca88da321a..e13039d836f 100644 --- a/test/JDBC/upgrade/13_8/schedule +++ b/test/JDBC/upgrade/13_8/schedule @@ -363,6 +363,8 @@ test_conv_string_to_smalldatetime-before-14_6 test_conv_string_to_time-before-17_4 BABEL-5031 test_conv_money_to_varchar +sp_xml_preparedocument +sp_xml_removedocument fixeddecimal_modulo BABEL-NUMERIC_EXPR test_conv_float_to_varchar_char_before_17_4 diff --git a/test/JDBC/upgrade/13_9/schedule b/test/JDBC/upgrade/13_9/schedule index a0ef21b12b2..801d9f5e5ed 100644 --- a/test/JDBC/upgrade/13_9/schedule +++ b/test/JDBC/upgrade/13_9/schedule @@ -368,6 +368,8 @@ test_conv_string_to_smalldatetime-before-14_6 test_conv_string_to_time-before-17_4 BABEL-5031 test_conv_money_to_varchar +sp_xml_preparedocument +sp_xml_removedocument fixeddecimal_modulo BABEL-NUMERIC_EXPR test_conv_float_to_varchar_char_before_17_4 diff --git a/test/JDBC/upgrade/14_10/schedule b/test/JDBC/upgrade/14_10/schedule index b161980d9a1..d903528486a 100644 --- a/test/JDBC/upgrade/14_10/schedule +++ b/test/JDBC/upgrade/14_10/schedule @@ -481,6 +481,8 @@ test_conv_string_to_smalldatetime test_conv_string_to_time-before-17_4 BABEL-5031 test_conv_money_to_varchar +sp_xml_preparedocument +sp_xml_removedocument fixeddecimal_modulo BABEL-NUMERIC_EXPR BABEL-5467 diff --git a/test/JDBC/upgrade/14_11/schedule b/test/JDBC/upgrade/14_11/schedule index 2a91e8310a7..0309292e4be 100644 --- a/test/JDBC/upgrade/14_11/schedule +++ b/test/JDBC/upgrade/14_11/schedule @@ -479,6 +479,8 @@ test_conv_string_to_smalldatetime test_conv_string_to_time-before-17_4 BABEL-5031 test_conv_money_to_varchar +sp_xml_preparedocument +sp_xml_removedocument fixeddecimal_modulo BABEL-NUMERIC_EXPR BABEL-5467 diff --git a/test/JDBC/upgrade/14_12/schedule b/test/JDBC/upgrade/14_12/schedule index 025d0dbfbb7..dade8a0a33e 100644 --- a/test/JDBC/upgrade/14_12/schedule +++ b/test/JDBC/upgrade/14_12/schedule @@ -480,6 +480,8 @@ BABEL-5186 smalldatetime_date_cmp-before-15_5-16_1 BABEL-5031 test_conv_money_to_varchar +sp_xml_preparedocument +sp_xml_removedocument fixeddecimal_modulo BABEL-NUMERIC_EXPR BABEL-5467 diff --git a/test/JDBC/upgrade/14_13/schedule b/test/JDBC/upgrade/14_13/schedule index e0f76731076..3a050af3c3f 100644 --- a/test/JDBC/upgrade/14_13/schedule +++ b/test/JDBC/upgrade/14_13/schedule @@ -480,6 +480,8 @@ test_conv_string_to_smalldatetime test_conv_string_to_time-before-17_4 BABEL-5031 test_conv_money_to_varchar +sp_xml_preparedocument +sp_xml_removedocument fixeddecimal_modulo BABEL-NUMERIC_EXPR BABEL-5467 diff --git a/test/JDBC/upgrade/14_15/schedule b/test/JDBC/upgrade/14_15/schedule index d6da6c6dd69..493d8097a8e 100644 --- a/test/JDBC/upgrade/14_15/schedule +++ b/test/JDBC/upgrade/14_15/schedule @@ -476,6 +476,8 @@ test_conv_string_to_smalldatetime test_conv_string_to_time-before-17_4 BABEL-5031 test_conv_money_to_varchar +sp_xml_preparedocument +sp_xml_removedocument fixeddecimal_modulo BABEL-NUMERIC_EXPR test_conv_float_to_varchar_char_before_17_4 diff --git a/test/JDBC/upgrade/14_17/schedule b/test/JDBC/upgrade/14_17/schedule index dd7966ec2e9..a2d81e0740a 100644 --- a/test/JDBC/upgrade/14_17/schedule +++ b/test/JDBC/upgrade/14_17/schedule @@ -476,6 +476,8 @@ test_conv_string_to_smalldatetime test_conv_string_to_time-before-17_4 BABEL-5031 test_conv_money_to_varchar +sp_xml_preparedocument +sp_xml_removedocument fixeddecimal_modulo BABEL-NUMERIC_EXPR BABEL-5467 diff --git a/test/JDBC/upgrade/14_3/schedule b/test/JDBC/upgrade/14_3/schedule index 81eb3d62bc0..e3c3279f12c 100644 --- a/test/JDBC/upgrade/14_3/schedule +++ b/test/JDBC/upgrade/14_3/schedule @@ -399,6 +399,8 @@ test_conv_string_to_smalldatetime-before-14_6 test_conv_string_to_time-before-17_4 BABEL-5031 test_conv_money_to_varchar +sp_xml_preparedocument +sp_xml_removedocument fixeddecimal_modulo BABEL-NUMERIC_EXPR BABEL-5467 diff --git a/test/JDBC/upgrade/14_5/schedule b/test/JDBC/upgrade/14_5/schedule index cca508752d8..67239bf788b 100644 --- a/test/JDBC/upgrade/14_5/schedule +++ b/test/JDBC/upgrade/14_5/schedule @@ -411,6 +411,8 @@ test_conv_string_to_smalldatetime-before-14_6 test_conv_string_to_time-before-17_4 BABEL-5031 test_conv_money_to_varchar +sp_xml_preparedocument +sp_xml_removedocument fixeddecimal_modulo BABEL-NUMERIC_EXPR BABEL-5467 diff --git a/test/JDBC/upgrade/14_6/schedule b/test/JDBC/upgrade/14_6/schedule index 933df181d7c..6474435b59c 100644 --- a/test/JDBC/upgrade/14_6/schedule +++ b/test/JDBC/upgrade/14_6/schedule @@ -449,6 +449,8 @@ test_conv_string_to_smalldatetime test_conv_string_to_time-before-17_4 BABEL-5031 test_conv_money_to_varchar +sp_xml_preparedocument +sp_xml_removedocument fixeddecimal_modulo BABEL-NUMERIC_EXPR BABEL-5467 diff --git a/test/JDBC/upgrade/14_7/schedule b/test/JDBC/upgrade/14_7/schedule index 5714552461d..d7550773a80 100644 --- a/test/JDBC/upgrade/14_7/schedule +++ b/test/JDBC/upgrade/14_7/schedule @@ -471,6 +471,8 @@ test_conv_string_to_smalldatetime test_conv_string_to_time-before-17_4 BABEL-5031 test_conv_money_to_varchar +sp_xml_preparedocument +sp_xml_removedocument fixeddecimal_modulo BABEL-NUMERIC_EXPR BABEL-5467 diff --git a/test/JDBC/upgrade/14_8/schedule b/test/JDBC/upgrade/14_8/schedule index 1767697cff8..c455e9680c6 100644 --- a/test/JDBC/upgrade/14_8/schedule +++ b/test/JDBC/upgrade/14_8/schedule @@ -473,6 +473,8 @@ test_conv_string_to_smalldatetime test_conv_string_to_time-before-17_4 BABEL-5031 test_conv_money_to_varchar +sp_xml_preparedocument +sp_xml_removedocument fixeddecimal_modulo BABEL-NUMERIC_EXPR BABEL-5467 diff --git a/test/JDBC/upgrade/14_9/schedule b/test/JDBC/upgrade/14_9/schedule index 289084e6f65..9504a65a5b5 100644 --- a/test/JDBC/upgrade/14_9/schedule +++ b/test/JDBC/upgrade/14_9/schedule @@ -476,6 +476,8 @@ test_conv_string_to_smalldatetime test_conv_string_to_time-before-17_4 BABEL-5031 test_conv_money_to_varchar +sp_xml_preparedocument +sp_xml_removedocument fixeddecimal_modulo BABEL-NUMERIC_EXPR BABEL-5467 diff --git a/test/JDBC/upgrade/15_1/schedule b/test/JDBC/upgrade/15_1/schedule index 9e8d97b2d89..12916303b78 100644 --- a/test/JDBC/upgrade/15_1/schedule +++ b/test/JDBC/upgrade/15_1/schedule @@ -449,6 +449,8 @@ test_conv_string_to_smalldatetime test_conv_string_to_time-before-17_4 BABEL-5031 test_conv_money_to_varchar +sp_xml_preparedocument +sp_xml_removedocument fixeddecimal_modulo BABEL-NUMERIC_EXPR BABEL-5467 diff --git a/test/JDBC/upgrade/15_10/schedule b/test/JDBC/upgrade/15_10/schedule index 6916df5e267..b6a405aa154 100644 --- a/test/JDBC/upgrade/15_10/schedule +++ b/test/JDBC/upgrade/15_10/schedule @@ -567,6 +567,8 @@ test_conv_string_to_smalldatetime test_conv_string_to_time-before-17_4 BABEL-5031 test_conv_money_to_varchar +sp_xml_preparedocument +sp_xml_removedocument fixeddecimal_modulo BABEL-NUMERIC_EXPR BABEL-5467 diff --git a/test/JDBC/upgrade/15_12/schedule b/test/JDBC/upgrade/15_12/schedule index 003edb0c15e..9365dcf4daa 100644 --- a/test/JDBC/upgrade/15_12/schedule +++ b/test/JDBC/upgrade/15_12/schedule @@ -567,6 +567,8 @@ test_conv_string_to_smalldatetime test_conv_string_to_time-before-17_4 BABEL-5031 test_conv_money_to_varchar +sp_xml_preparedocument +sp_xml_removedocument fixeddecimal_modulo BABEL-NUMERIC_EXPR BABEL-5467 diff --git a/test/JDBC/upgrade/15_2/schedule b/test/JDBC/upgrade/15_2/schedule index ea76377aecd..62e179fd52c 100644 --- a/test/JDBC/upgrade/15_2/schedule +++ b/test/JDBC/upgrade/15_2/schedule @@ -485,6 +485,8 @@ test_conv_string_to_smalldatetime test_conv_string_to_time-before-17_4 BABEL-5031 test_conv_money_to_varchar +sp_xml_preparedocument +sp_xml_removedocument fixeddecimal_modulo BABEL-NUMERIC_EXPR BABEL-5467 diff --git a/test/JDBC/upgrade/15_3/schedule b/test/JDBC/upgrade/15_3/schedule index 63755c3b515..ac70aba4e8e 100644 --- a/test/JDBC/upgrade/15_3/schedule +++ b/test/JDBC/upgrade/15_3/schedule @@ -505,6 +505,8 @@ test_conv_string_to_smalldatetime test_conv_string_to_time-before-17_4 BABEL-5031 test_conv_money_to_varchar +sp_xml_preparedocument +sp_xml_removedocument fixeddecimal_modulo BABEL-NUMERIC_EXPR BABEL-5467 diff --git a/test/JDBC/upgrade/15_4/schedule b/test/JDBC/upgrade/15_4/schedule index dfe44b0646b..26be5abb660 100644 --- a/test/JDBC/upgrade/15_4/schedule +++ b/test/JDBC/upgrade/15_4/schedule @@ -518,6 +518,8 @@ test_conv_string_to_smalldatetime test_conv_string_to_time-before-17_4 BABEL-5031 test_conv_money_to_varchar +sp_xml_preparedocument +sp_xml_removedocument fixeddecimal_modulo BABEL-NUMERIC_EXPR BABEL-5467 diff --git a/test/JDBC/upgrade/15_5/schedule b/test/JDBC/upgrade/15_5/schedule index 9aa519d7888..f544c0595ad 100644 --- a/test/JDBC/upgrade/15_5/schedule +++ b/test/JDBC/upgrade/15_5/schedule @@ -552,6 +552,8 @@ test_conv_string_to_smalldatetime test_conv_string_to_time-before-17_4 BABEL-5031 test_conv_money_to_varchar +sp_xml_preparedocument +sp_xml_removedocument fixeddecimal_modulo BABEL-NUMERIC_EXPR test_conv_float_to_varchar_char_before_17_4 diff --git a/test/JDBC/upgrade/15_6/schedule b/test/JDBC/upgrade/15_6/schedule index 64e578be1fc..9989782024a 100644 --- a/test/JDBC/upgrade/15_6/schedule +++ b/test/JDBC/upgrade/15_6/schedule @@ -567,6 +567,8 @@ test_conv_string_to_smalldatetime test_conv_string_to_time-before-17_4 BABEL-5031 test_conv_money_to_varchar +sp_xml_preparedocument +sp_xml_removedocument fixeddecimal_modulo BABEL-NUMERIC_EXPR BABEL-5467 diff --git a/test/JDBC/upgrade/15_7/schedule b/test/JDBC/upgrade/15_7/schedule index 80aaf874e39..83acbc8a54b 100644 --- a/test/JDBC/upgrade/15_7/schedule +++ b/test/JDBC/upgrade/15_7/schedule @@ -575,6 +575,8 @@ test_conv_string_to_smalldatetime test_conv_string_to_time-before-17_4 BABEL-5031 test_conv_money_to_varchar +sp_xml_preparedocument +sp_xml_removedocument fixeddecimal_modulo BABEL-NUMERIC_EXPR BABEL-5467 diff --git a/test/JDBC/upgrade/15_8/schedule b/test/JDBC/upgrade/15_8/schedule index 296cd6a5d97..348f9c59205 100644 --- a/test/JDBC/upgrade/15_8/schedule +++ b/test/JDBC/upgrade/15_8/schedule @@ -567,6 +567,8 @@ test_conv_string_to_smalldatetime test_conv_string_to_time-before-17_4 BABEL-5031 test_conv_money_to_varchar +sp_xml_preparedocument +sp_xml_removedocument fixeddecimal_modulo BABEL-NUMERIC_EXPR BABEL-5467 diff --git a/test/JDBC/upgrade/16_1/schedule b/test/JDBC/upgrade/16_1/schedule index 3e73dceabe8..fbe934343a8 100644 --- a/test/JDBC/upgrade/16_1/schedule +++ b/test/JDBC/upgrade/16_1/schedule @@ -560,6 +560,8 @@ test_conv_string_to_smalldatetime test_conv_string_to_time-before-17_4 BABEL-5031 test_conv_money_to_varchar +sp_xml_preparedocument +sp_xml_removedocument fixeddecimal_modulo BABEL-NUMERIC_EXPR test_conv_float_to_varchar_char_before_17_4 diff --git a/test/JDBC/upgrade/16_10/schedule b/test/JDBC/upgrade/16_10/schedule index 401e413257d..9c973388d73 100644 --- a/test/JDBC/upgrade/16_10/schedule +++ b/test/JDBC/upgrade/16_10/schedule @@ -602,6 +602,8 @@ test_conv_string_to_time-before-17_4 db_owner BABEL-5031 test_conv_money_to_varchar +sp_xml_preparedocument +sp_xml_removedocument fixeddecimal_modulo BABEL-NUMERIC_EXPR test_conv_float_to_varchar_char diff --git a/test/JDBC/upgrade/16_2/schedule b/test/JDBC/upgrade/16_2/schedule index 384f2d801bc..c4e3dff6761 100644 --- a/test/JDBC/upgrade/16_2/schedule +++ b/test/JDBC/upgrade/16_2/schedule @@ -576,6 +576,8 @@ test_conv_string_to_smalldatetime test_conv_string_to_time-before-17_4 BABEL-5031 test_conv_money_to_varchar +sp_xml_preparedocument +sp_xml_removedocument fixeddecimal_modulo BABEL-NUMERIC_EXPR test_conv_float_to_varchar_char_before_17_4 diff --git a/test/JDBC/upgrade/16_3/schedule b/test/JDBC/upgrade/16_3/schedule index 1480bfc8a6c..3c77c5f6eff 100644 --- a/test/JDBC/upgrade/16_3/schedule +++ b/test/JDBC/upgrade/16_3/schedule @@ -579,6 +579,8 @@ test_conv_string_to_smalldatetime test_conv_string_to_time-before-17_4 BABEL-5031 test_conv_money_to_varchar +sp_xml_preparedocument +sp_xml_removedocument fixeddecimal_modulo BABEL-NUMERIC_EXPR test_conv_float_to_varchar_char_before_17_4 diff --git a/test/JDBC/upgrade/16_4/schedule b/test/JDBC/upgrade/16_4/schedule index bc60e4a9e93..352437cd8cf 100644 --- a/test/JDBC/upgrade/16_4/schedule +++ b/test/JDBC/upgrade/16_4/schedule @@ -593,6 +593,8 @@ test_conv_string_to_smalldatetime test_conv_string_to_time-before-17_4 BABEL-5031 test_conv_money_to_varchar +sp_xml_preparedocument +sp_xml_removedocument fixeddecimal_modulo BABEL-NUMERIC_EXPR test_conv_float_to_varchar_char_before_17_4 diff --git a/test/JDBC/upgrade/16_6/schedule b/test/JDBC/upgrade/16_6/schedule index 5fa3a8d8651..3b31cea553e 100644 --- a/test/JDBC/upgrade/16_6/schedule +++ b/test/JDBC/upgrade/16_6/schedule @@ -596,6 +596,8 @@ test_conv_string_to_smalldatetime test_conv_string_to_time-before-17_4 BABEL-5031 test_conv_money_to_varchar +sp_xml_preparedocument +sp_xml_removedocument fixeddecimal_modulo BABEL-NUMERIC_EXPR test_conv_float_to_varchar_char_before_17_4 diff --git a/test/JDBC/upgrade/16_9/schedule b/test/JDBC/upgrade/16_9/schedule index 648ed276d36..12968d1d283 100644 --- a/test/JDBC/upgrade/16_9/schedule +++ b/test/JDBC/upgrade/16_9/schedule @@ -602,6 +602,8 @@ test_conv_string_to_time-before-17_4 db_owner BABEL-5031 test_conv_money_to_varchar +sp_xml_preparedocument +sp_xml_removedocument fixeddecimal_modulo BABEL-NUMERIC_EXPR test_conv_float_to_varchar_char diff --git a/test/JDBC/upgrade/latest/schedule b/test/JDBC/upgrade/latest/schedule index 17635c25346..7cb30b9c637 100644 --- a/test/JDBC/upgrade/latest/schedule +++ b/test/JDBC/upgrade/latest/schedule @@ -603,6 +603,8 @@ smalldatetime_date_cmp BABEL-2961 BABEL-5031 test_conv_money_to_varchar +sp_xml_preparedocument +sp_xml_removedocument fixeddecimal_modulo BABEL-NUMERIC_EXPR test_conv_float_to_varchar_char diff --git a/test/python/expected/sql_validation_framework/expected_create.out b/test/python/expected/sql_validation_framework/expected_create.out index bec807e2b37..72f464cfc6b 100644 --- a/test/python/expected/sql_validation_framework/expected_create.out +++ b/test/python/expected/sql_validation_framework/expected_create.out @@ -191,7 +191,6 @@ Could not find upgrade tests for procedure sys.sp_cursor_list Could not find upgrade tests for procedure sys.sp_describe_cursor Could not find upgrade tests for procedure sys.sp_oledb_ro_usrname Could not find upgrade tests for procedure sys.sp_prepare -Could not find upgrade tests for procedure sys.sp_reset_connection Could not find upgrade tests for procedure sys.sp_unprepare Could not find upgrade tests for procedure sys.sp_updatestats Could not find upgrade tests for table sys.babelfish_configurations From 9deec91599962a9e4d62028f7e5ef685861435d0 Mon Sep 17 00:00:00 2001 From: Harsh Dubey Date: Tue, 10 Jun 2025 11:38:53 +0000 Subject: [PATCH 02/40] Add the changes of stored procedures Signed-off-by: Harsh Dubey --- contrib/babelfishpg_tsql/src/pltsql.h | 1 - 1 file changed, 1 deletion(-) diff --git a/contrib/babelfishpg_tsql/src/pltsql.h b/contrib/babelfishpg_tsql/src/pltsql.h index 58d3df6feda..e58edbed7f4 100644 --- a/contrib/babelfishpg_tsql/src/pltsql.h +++ b/contrib/babelfishpg_tsql/src/pltsql.h @@ -1812,7 +1812,6 @@ typedef struct PLtsql_protocol_plugin - int32 (*get_numeric_typmod_from_exp) (Plan *plan, Node *expr); int32 (*get_numeric_typmod_from_exp) (Plan *plan, Node *expr, bool *found); /* Session level GUCs */ bool quoted_identifier; From 793f7c3bd2627887f7639b714845faa6019e9eff Mon Sep 17 00:00:00 2001 From: Harsh Dubey Date: Tue, 10 Jun 2025 13:25:42 +0000 Subject: [PATCH 03/40] Fixed the upgrade file to add the changes of stored procedures Signed-off-by: Harsh Dubey --- .../babelfishpg_tsql--5.1.0--5.2.0.sql | 25 ------------------- 1 file changed, 25 deletions(-) diff --git a/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--5.1.0--5.2.0.sql b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--5.1.0--5.2.0.sql index d0db8fd8b53..e23e02b3b28 100644 --- a/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--5.1.0--5.2.0.sql +++ b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--5.1.0--5.2.0.sql @@ -1553,31 +1553,6 @@ GRANT SELECT ON sys.dm_os_sys_info TO PUBLIC; -- Please have this be one of the last statements executed in this upgrade script. DROP PROCEDURE sys.babelfish_drop_deprecated_object(varchar, varchar, varchar); --- BBF_XML_HANDLES --- This catalog table stores the metadata of the XML handles generated across various sessions. -CREATE TABLE sys.babelfish_xml_handles ( - session_id INT NOT NULL, -- The Session ID of the session that holds this XML document handle. - document_id INT NOT NULL, -- XML document handle ID returned by sp_xml_preparedocument. - namespace_document_id INT NULL, -- Internal handle ID assigned to xpath_namespaces (NULL if there is no namespace document.) - Xml_content XML, -- The given XML doc stored in xml format - NamespaceDefinitions XML, -- The given xpath_namespaces in xml format - original_document_size_bytes BIGINT NULL, -- Size of the original XML document in bytes. - original_namespace_document_size_bytes BIGINT NULL, -- Size of the original XML namespace document, in bytes. NULL if there is no namespace document. - sql_handle BYTEA NULL, - statement_start_offset INT NULL, - statement_end_offset INT NULL, - num_openxml_calls BIGINT NULL, -- Number of OPENXML calls with this document handle. - row_count BIGINT NULL, -- Number of rows returned by all previous OPENXML calls for this document handle. - creation_time sys.datetime NULL, --Timestamp when sp_xml_preparedocument was called. - openxml_last_calltime sys.datetime NULL ,-- Timestamp of the last OPENXML call - PRIMARY KEY(session_id, document_id) -); - --- SEQUENCE to maintain the ID of XML handles. -CREATE SEQUENCE sys.babelfish_xml_handles_seq START 1 INCREMENT 2 MAXVALUE 2147483647 CYCLE; - -GRANT SELECT ON sys.babelfish_xml_handles TO PUBLIC; - CREATE OR REPLACE PROCEDURE sys.sp_xml_preparedocument( INOUT "@hdoc" INTEGER, IN "@xmltext" sys.VARCHAR DEFAULT NULL, From adcabd0d92f27b19ac276a4cac7719bccfec7e3f Mon Sep 17 00:00:00 2001 From: Harsh Dubey Date: Tue, 10 Jun 2025 18:29:55 +0000 Subject: [PATCH 04/40] Add support for openxml Signed-off-by: Harsh Dubey --- .../babelfishpg_tsql/sql/sys_functions.sql | 10 + .../babelfishpg_tsql--5.1.0--5.2.0.sql | 10 + .../src/backend_parser/gram-tsql-decl.y | 7 +- .../src/backend_parser/gram-tsql-rule.y | 117 ++++++++ .../src/backend_parser/kwlist.h | 1 + .../src/backend_parser/parser.c | 2 + contrib/babelfishpg_tsql/src/hooks.c | 155 ++++++++++ contrib/babelfishpg_tsql/src/procedures.c | 119 ++++++++ contrib/babelfishpg_tsql/src/tsqlIface.cpp | 10 + .../src/tsqlUnsupportedFeatureHandler.cpp | 2 +- .../openxml_with_clause-vu-verify.out | 282 ++++++++++++++++++ .../xml/openxml_with_clause-vu-verify.sql | 231 ++++++++++++++ test/JDBC/upgrade/13_4/schedule | 2 + test/JDBC/upgrade/13_5/schedule | 1 + test/JDBC/upgrade/13_6/schedule | 1 + test/JDBC/upgrade/13_7/schedule | 1 + test/JDBC/upgrade/13_8/schedule | 1 + test/JDBC/upgrade/13_9/schedule | 1 + test/JDBC/upgrade/14_10/schedule | 1 + test/JDBC/upgrade/14_11/schedule | 1 + test/JDBC/upgrade/14_12/schedule | 1 + test/JDBC/upgrade/14_13/schedule | 1 + test/JDBC/upgrade/14_15/schedule | 1 + test/JDBC/upgrade/14_17/schedule | 1 + test/JDBC/upgrade/14_3/schedule | 1 + test/JDBC/upgrade/14_5/schedule | 1 + test/JDBC/upgrade/14_6/schedule | 1 + test/JDBC/upgrade/14_7/schedule | 1 + test/JDBC/upgrade/14_8/schedule | 1 + test/JDBC/upgrade/14_9/schedule | 1 + test/JDBC/upgrade/15_1/schedule | 1 + test/JDBC/upgrade/15_10/schedule | 1 + test/JDBC/upgrade/15_12/schedule | 1 + test/JDBC/upgrade/15_2/schedule | 1 + test/JDBC/upgrade/15_3/schedule | 1 + test/JDBC/upgrade/15_4/schedule | 1 + test/JDBC/upgrade/15_5/schedule | 1 + test/JDBC/upgrade/15_6/schedule | 1 + test/JDBC/upgrade/15_7/schedule | 1 + test/JDBC/upgrade/15_8/schedule | 1 + test/JDBC/upgrade/16_1/schedule | 1 + test/JDBC/upgrade/16_10/schedule | 1 + test/JDBC/upgrade/16_2/schedule | 1 + test/JDBC/upgrade/16_3/schedule | 1 + test/JDBC/upgrade/16_4/schedule | 1 + test/JDBC/upgrade/16_6/schedule | 1 + test/JDBC/upgrade/16_9/schedule | 1 + test/JDBC/upgrade/latest/schedule | 1 + 48 files changed, 980 insertions(+), 3 deletions(-) create mode 100644 test/JDBC/expected/openxml_with_clause-vu-verify.out create mode 100644 test/JDBC/input/xml/openxml_with_clause-vu-verify.sql diff --git a/contrib/babelfishpg_tsql/sql/sys_functions.sql b/contrib/babelfishpg_tsql/sql/sys_functions.sql index 411d79f8c1f..b9ae1f60da7 100644 --- a/contrib/babelfishpg_tsql/sql/sys_functions.sql +++ b/contrib/babelfishpg_tsql/sql/sys_functions.sql @@ -3998,6 +3998,16 @@ CREATE OR REPLACE FUNCTION sys.openjson_with(json_string text, path text, VARIAD RETURNS SETOF RECORD AS 'babelfishpg_tsql', 'tsql_openjson_with' LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE; +CREATE OR REPLACE FUNCTION sys.tsql_openxml_get_xmldoc(int) +RETURNS xml +AS 'babelfishpg_tsql', 'tsql_openxml_get_xmldoc' +LANGUAGE C STRICT; + +CREATE OR REPLACE FUNCTION sys.tsql_openxml_get_colpattern(text,int) +RETURNS sys.nvarchar +AS 'babelfishpg_tsql', 'tsql_openxml_get_colpattern' +LANGUAGE C STRICT; + CREATE OR REPLACE FUNCTION sys.sp_datatype_info_helper( IN odbcVer smallint, IN is_100 bool, diff --git a/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--5.1.0--5.2.0.sql b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--5.1.0--5.2.0.sql index e23e02b3b28..cd09fd92766 100644 --- a/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--5.1.0--5.2.0.sql +++ b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--5.1.0--5.2.0.sql @@ -1573,6 +1573,16 @@ GRANT EXECUTE ON PROCEDURE sys.sp_xml_removedocument( IN INTEGER ) TO PUBLIC; +CREATE OR REPLACE FUNCTION sys.tsql_openxml_get_xmldoc(int) +RETURNS xml +AS 'babelfishpg_tsql', 'tsql_openxml_get_xmldoc' +LANGUAGE C STRICT; + +CREATE OR REPLACE FUNCTION sys.tsql_openxml_get_colpattern(text,int) +RETURNS sys.nvarchar +AS 'babelfishpg_tsql', 'tsql_openxml_get_colpattern' +LANGUAGE C STRICT; + -- After upgrade, always run analyze for all babelfish catalogs. CALL sys.analyze_babelfish_catalogs(); -- Reset search_path to not affect any subsequent scripts diff --git a/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-decl.y b/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-decl.y index b721d8cc2a1..53894a447a9 100644 --- a/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-decl.y +++ b/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-decl.y @@ -41,6 +41,9 @@ %type openjson_col_defs %type optional_path %type optional_asJson +%type openxml_expr +%type openxml_column_list +%type openxml_column_el %type tsql_opt_arg_dflt %type tsql_opt_null_keyword @@ -117,7 +120,7 @@ TSQL_NOCHECK TSQL_NOLOCK TSQL_READUNCOMMITTED TSQL_UPDLOCK TSQL_REPEATABLEREAD TSQL_READCOMMITTED TSQL_TABLOCK TSQL_TABLOCKX TSQL_PAGLOCK TSQL_ROWLOCK TSQL_TOP TSQL_PERCENT - TSQL_AUTO TSQL_EXPLICIT TSQL_RAW TSQL_PATH TSQL_FOR TSQL_BASE64 TSQL_ROOT TSQL_READPAST TSQL_XLOCK TSQL_NOEXPAND OPENJSON JSON_MODIFY + TSQL_AUTO TSQL_EXPLICIT TSQL_RAW TSQL_PATH TSQL_FOR TSQL_BASE64 TSQL_ROOT TSQL_READPAST TSQL_XLOCK TSQL_NOEXPAND OPENJSON OPENXML JSON_MODIFY TSQL_JSON TSQL_INCLUDE_NULL_VALUES TSQL_WITHOUT_ARRAY_WRAPPER TSQL_MEMBER TSQL_SERVER TSQL_WINDOWS TSQL_CERTIFICATE TSQL_DEFAULT_DATABASE TSQL_DEFAULT_LANGUAGE TSQL_HASHED @@ -134,6 +137,6 @@ * otherwise the parser cannot tell between 'WITH' and 'WITH (' and thus * lead to a shift/reduce conflict. */ -%token WITH_paren TSQL_HINT_START_BRACKET UPDATE_paren +%token WITH_paren TSQL_HINT_START_BRACKET UPDATE_paren WITH_table %left TSQL_CROSS TSQL_OUTER TSQL_UNPIVOT diff --git a/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-rule.y b/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-rule.y index b59372fdc78..a45f27c4069 100644 --- a/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-rule.y +++ b/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-rule.y @@ -1779,6 +1779,20 @@ table_ref: relation_expr tsql_table_hint_expr */ $$ = (Node *) $1; } + | TSQL_APPLY openxml_expr + { + /* + * This case handles openxml cross/outer apply + */ + $$ = (Node *) $2; + } + | openxml_expr + { + /* + * Standard openxml case + */ + $$ = (Node *) $1; + } | table_ref TSQL_UNPIVOT tsql_unpivot_clause alias_clause { List *unpivot_info = list_make3($1, (List *)$3, $4); @@ -1786,6 +1800,109 @@ table_ref: relation_expr tsql_table_hint_expr } ; +openxml_expr: OPENXML '(' a_expr ',' a_expr ')' opt_alias_clause + { + Openxml_expr *n = makeNode(Openxml_expr); + n->tsql_docid = $3; + n->rowexpr = $5; + n->alias = $7; + n->columns = TsqlMakeOpenxmlColList(); + n->location = @1; + $$ = (Node *) n; + } + | OPENXML '(' a_expr ',' a_expr ',' a_expr ')' opt_alias_clause + { + Openxml_expr *n = makeNode(Openxml_expr); + n->tsql_docid = $3; + n->rowexpr = $5; + n->tsql_flag = $7; + n->columns = TsqlMakeOpenxmlColList(); + n->alias = $9; + n->location = @1; + $$ = (Node *) n; + } + | OPENXML '(' a_expr ',' a_expr ')' WITH_table TABLE qualified_name opt_alias_clause + { + Openxml_expr *n = makeNode(Openxml_expr); + n->tsql_docid = $3; + n->rowexpr = $5; + n->table_ref = $9; + n->alias = $10; + n->location = @1; + /* Default flag is 0 when not specified */ + n->tsql_flag = makeIntConst(0, -1); + $$ = (Node *) n; + } + | OPENXML '(' a_expr ',' a_expr ',' a_expr ')' WITH_table TABLE qualified_name opt_alias_clause + { + Openxml_expr *n = makeNode(Openxml_expr); + n->tsql_docid = $3; + n->rowexpr = $5; + n->tsql_flag = $7; + n->table_ref = $11; + n->alias = $12; + n->location = @1; + $$ = (Node *) n; + } + | OPENXML '(' a_expr ',' a_expr ')' WITH_paren '(' openxml_column_list ')' opt_alias_clause + { + Openxml_expr *n = makeNode(Openxml_expr); + n->tsql_docid = $3; + n->rowexpr = $5; + n->columns = $9; + n->alias = $11; + n->table_ref = NULL; + n->location = @1; + /* Default flag is 0 when not specified */ + n->tsql_flag = makeIntConst(0, -1); + $$ = (Node *) n; + } + | OPENXML '(' a_expr ',' a_expr ',' a_expr ')' WITH_paren '(' openxml_column_list ')' opt_alias_clause + { + Openxml_expr *n = makeNode(Openxml_expr); + n->tsql_docid = $3; + n->rowexpr = $5; + n->tsql_flag = $7; + n->columns = $11; + n->alias = $13; + n->table_ref = NULL; + n->location = @1; + $$ = (Node *) n; + } + ; + +openxml_column_list: openxml_column_el { $$ = list_make1($1); } + | openxml_column_list ',' openxml_column_el { $$ = lappend($1, $3); } + ; + +openxml_column_el: + ColId Typename + { + RangeTableFuncCol *fc = makeNode(RangeTableFuncCol); + + fc->colname = $1; + fc->typeName = $2; + /* Set a default XPath expression based on column name */ + /* fc->colexpr = (Node *) makeStringConst(psprintf("@%s", $1), @1); */ + /* fc->colexpr = makeStringConst($1, @1); */ + fc->colexpr = NULL; + fc->location = @1; + + $$ = (Node *) fc; + } + | ColId Typename Sconst + { + RangeTableFuncCol *fc = makeNode(RangeTableFuncCol); + fc->colname = $1; + fc->typeName = $2; + fc->colexpr = (Node *) makeStringConst($3, @1); + fc->location = @1; + + $$ = (Node *) fc; + } + ; + + openjson_expr: OPENJSON '(' a_expr ')' opt_alias_clause { RangeFunction *n = makeNode(RangeFunction); diff --git a/contrib/babelfishpg_tsql/src/backend_parser/kwlist.h b/contrib/babelfishpg_tsql/src/backend_parser/kwlist.h index 063f381df0f..7dd24712dba 100644 --- a/contrib/babelfishpg_tsql/src/backend_parser/kwlist.h +++ b/contrib/babelfishpg_tsql/src/backend_parser/kwlist.h @@ -323,6 +323,7 @@ PG_KEYWORD("old_password", TSQL_OLD_PASSWORD, UNRESERVED_KEYWORD) PG_KEYWORD("on", ON, RESERVED_KEYWORD) PG_KEYWORD("only", ONLY, RESERVED_KEYWORD) PG_KEYWORD("openjson", OPENJSON, COL_NAME_KEYWORD) +PG_KEYWORD("openxml", OPENXML, COL_NAME_KEYWORD) PG_KEYWORD("operator", OPERATOR, UNRESERVED_KEYWORD) PG_KEYWORD("option", OPTION, RESERVED_KEYWORD) PG_KEYWORD("options", OPTIONS, UNRESERVED_KEYWORD) diff --git a/contrib/babelfishpg_tsql/src/backend_parser/parser.c b/contrib/babelfishpg_tsql/src/backend_parser/parser.c index a25fca6f3a6..4ae9d3ad2a6 100644 --- a/contrib/babelfishpg_tsql/src/backend_parser/parser.c +++ b/contrib/babelfishpg_tsql/src/backend_parser/parser.c @@ -266,6 +266,8 @@ pgtsql_base_yylex(YYSTYPE *lvalp, YYLTYPE * llocp, core_yyscan_t yyscanner) case '(': cur_token = WITH_paren; break; + case TABLE: + cur_token = WITH_table; } break; case '(': diff --git a/contrib/babelfishpg_tsql/src/hooks.c b/contrib/babelfishpg_tsql/src/hooks.c index 2397dd0da28..663bfba8afb 100644 --- a/contrib/babelfishpg_tsql/src/hooks.c +++ b/contrib/babelfishpg_tsql/src/hooks.c @@ -250,6 +250,7 @@ static char* pltsql_get_object_identity_event_trigger(ObjectAddress *addr); static const char *remove_db_name_in_schema(const char *schema_name, const char *object_type); static int32 pltsql_exprTypmod(Plan *plan, Node *expr); static Oid get_domain_typmodin(Type typ); +static Node* bbf_transformFromClauseItem(ParseState *pstate, Node *n, ParseNamespaceItem **top_nsitem, List **namespace); /*************************************************** * Temp Table Related Declarations + Hooks @@ -303,6 +304,7 @@ static match_pltsql_func_call_hook_type prev_match_pltsql_func_call_hook = NULL; static insert_pltsql_function_defaults_hook_type prev_insert_pltsql_function_defaults_hook = NULL; static replace_pltsql_function_defaults_hook_type prev_replace_pltsql_function_defaults_hook = NULL; static exprTypmod_hook_type prev_exprTypmod_hook = NULL; +static transformFromClauseItem_hook_type prev_transformFromClauseItem_hook = NULL; static print_pltsql_function_arguments_hook_type prev_print_pltsql_function_arguments_hook = NULL; static planner_hook_type prev_planner_hook = NULL; static transform_check_constraint_expr_hook_type prev_transform_check_constraint_expr_hook = NULL; @@ -466,6 +468,9 @@ InstallExtendedHooks(void) prev_exprTypmod_hook = exprTypmod_hook; exprTypmod_hook = pltsql_exprTypmod; + prev_transformFromClauseItem_hook = transformFromClauseItem_hook; + transformFromClauseItem_hook = bbf_transformFromClauseItem; + prev_print_pltsql_function_arguments_hook = print_pltsql_function_arguments_hook; print_pltsql_function_arguments_hook = print_pltsql_function_arguments; @@ -631,6 +636,7 @@ UninstallExtendedHooks(void) insert_pltsql_function_defaults_hook = prev_insert_pltsql_function_defaults_hook; replace_pltsql_function_defaults_hook = prev_replace_pltsql_function_defaults_hook; exprTypmod_hook = prev_exprTypmod_hook; + transformFromClauseItem_hook = prev_transformFromClauseItem_hook; print_pltsql_function_arguments_hook = prev_print_pltsql_function_arguments_hook; planner_hook = prev_planner_hook; transform_check_constraint_expr_hook = prev_transform_check_constraint_expr_hook; @@ -6519,6 +6525,155 @@ pltsql_exprTypmod(Plan *plan, Node *expr) return result_typmod; } +/* + * fetch_table_schema - Get column definitions from an existing table + * + * This function retrieves column information from a specified table and + * creates RangeTableFuncCol nodes for each column. These are then used + * in the OPENXML WITH table_name syntax to define the output columns. + */ + +static List * +fetch_table_schema(RangeVar *relation, Node *flag) +{ + List *columns = NIL; + + if (relation != NULL) + { + Relation rel; + TupleDesc tupdesc; + int i; + + /* Open the relation to get its schema */ + rel = relation_openrv(relation, AccessShareLock); + + if (rel == NULL) + { + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_TABLE), + errmsg("table \"%s\" does not exist", + relation->relname))); + } + + /* Get the tuple descriptor which contains column information */ + tupdesc = RelationGetDescr(rel); + + /* Create RangeTableFuncCol nodes from the table's columns */ + for (i = 0; i < tupdesc->natts; i++) + { + Form_pg_attribute att = TupleDescAttr(tupdesc, i); + RangeTableFuncCol *fc; + char *colname; + + /* Skip system columns and dropped columns */ + if (att->attisdropped || att->attnum < 0) + continue; + + colname = NameStr(att->attname); + + /* Create a column definition */ + fc = makeNode(RangeTableFuncCol); + fc->colname = pstrdup(colname); + + /* Create a TypeName node for the column type */ + fc->typeName = makeTypeNameFromOid(att->atttypid, att->atttypmod); + + /* Set the column expression to the generated XPath */ + fc->colexpr = (Node *) makeFuncCall(list_make2(makeString("sys"), makeString("tsql_openxml_get_colpattern")), + list_make2(makeStringConst(colname, -1), flag), + COERCE_EXPLICIT_CALL, + -1); + fc->coldefexpr = NULL; + fc->location = -1; + + columns = lappend(columns, fc); + } + + /* Close the relation */ + relation_close(rel, AccessShareLock); + } + + return columns; +} + +static void +transformOpenxml_expr(ParseState *pstate, Openxml_expr *expr) +{ + + /* If a table reference was provided, get the columns from that table */ + if (expr->table_ref != NULL) + { + /* Fetch the table schema and generate column definitions with appropriate XPath expressions */ + expr->columns = fetch_table_schema(expr->table_ref, expr->tsql_flag); + } + else if (expr->columns != NIL) + { + /* Handle case where columns are provided but no table name */ + ListCell *lc; + foreach(lc, expr->columns) + { + RangeTableFuncCol *fc = (RangeTableFuncCol *) lfirst(lc); + + /* If no column expression is provided, generate one based on the flag */ + if (fc->colexpr == NULL) + { + /* + * To get original column name, utilize location of ColumnDef and query + * string. + */ + const char *column_name_start = pstate->p_sourcetext + fc->location; + char *original_name = extract_identifier(column_name_start, NULL); + + fc->colexpr = (Node *) makeFuncCall(list_make2(makeString("sys"), makeString("tsql_openxml_get_colpattern")), + list_make2(makeStringConst(original_name, -1), expr->tsql_flag), + COERCE_EXPLICIT_CALL, + -1); + } + } + } + +} + +static Node * +bbf_transformFromClauseItem(ParseState *pstate, Node *n, + ParseNamespaceItem **top_nsitem, + List **namespace) +{ + if (sql_dialect != SQL_DIALECT_TSQL) + return NULL; + + if (IsA(n, Openxml_expr)) + { + /* table function is like a plain relation */ + RangeTblRef *rtr; + ParseNamespaceItem *nsitem; + RangeTableFunc *rtf = makeNode(RangeTableFunc); + Openxml_expr *expr = (Openxml_expr *) n; + + transformOpenxml_expr(pstate, expr); + rtf->docexpr = (Node *) makeFuncCall(list_make2(makeString("sys"), makeString("tsql_openxml_get_xmldoc")), + list_make1(expr->tsql_docid), + COERCE_EXPLICIT_CALL, + -1); + // rtf->docexpr = (Node *) tsql_openxml_get_xmldoc(expr->tsql_docid); + rtf->rowexpr = expr->rowexpr; + rtf->columns = expr->columns; + rtf->alias = expr->alias; + rtf->location = expr->location; + rtf->namespaces = NIL; + + nsitem = bbf_transformRangeTableFunc(pstate, rtf); + + *top_nsitem = nsitem; + *namespace = list_make1(nsitem); + rtr = makeNode(RangeTblRef); + rtr->rtindex = nsitem->p_rtindex; + return (Node *) rtr; + } + + return NULL; +} + /* * pltsql_ExecUpdateResultTypeTL * diff --git a/contrib/babelfishpg_tsql/src/procedures.c b/contrib/babelfishpg_tsql/src/procedures.c index 09387a26e22..ea760d48d3e 100644 --- a/contrib/babelfishpg_tsql/src/procedures.c +++ b/contrib/babelfishpg_tsql/src/procedures.c @@ -50,6 +50,7 @@ #include "tsearch/ts_locale.h" #include "utils/xml.h" #include "common/md5.h" +#include "utils/datum.h" #include "catalog.h" #include "catalog/toasting.h" @@ -4937,4 +4938,122 @@ sp_xml_removedocument(PG_FUNCTION_ARGS) delete_xml_handle_entry(doc_handle); PG_RETURN_VOID(); +} + +PG_FUNCTION_INFO_V1(tsql_openxml_get_xmldoc); + +/* + * Function to retrieve XML document from temporary table using document ID + */ +Datum +tsql_openxml_get_xmldoc(PG_FUNCTION_ARGS) +{ + int32 document_id = PG_GETARG_INT32(0); + Relation relation; + ScanKeyData skey[1]; + TableScanDesc scan; + HeapTuple tuple; + bool found = false; + Datum result = (Datum) 0; + bool isnull = true; + EphemeralNamedRelation enr = NULL; + + + /* Check if the temporary table exists */ + if (xml_handle_temp_table_name != NULL) + { + enr = get_ENR(currentQueryEnv, xml_handle_temp_table_name, true); + if (enr) + { + relation = relation_open(enr->md.reliddesc, RowExclusiveLock); + } + } + + + if (!OidIsValid(enr->md.reliddesc)) + { + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("XML document with ID %d not found", document_id))); + } + + /* Open the relation */ + relation = relation_open(enr->md.reliddesc, AccessShareLock); + + /* Set up the scan key */ + ScanKeyInit(&skey[0], + 1, /* Column number */ + BTEqualStrategyNumber, F_INT4EQ, + Int32GetDatum(document_id)); + + /* Start the scan */ + scan = table_beginscan_catalog(relation, 1, skey); + tuple = heap_getnext(scan, ForwardScanDirection); + + /* Find the document */ + if (HeapTupleIsValid(tuple)) + { + /* Get the XML document from column 6 (doc) */ + result = heap_getattr(tuple, 6, RelationGetDescr(relation), &isnull); + + if (!isnull) + { + /* Make a copy of the value */ + result = datumCopy(result, false, -1); + found = true; + } + } + + /* Clean up */ + table_endscan(scan); + relation_close(relation, AccessShareLock); + + /* If we found the document, return it */ + if (found) + PG_RETURN_DATUM(result); + + /* Otherwise, throw an error */ + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("XML document with ID %d not found", document_id))); + + PG_RETURN_NULL(); /* Never reached */ +} + +/* + * Generate XPath expression for a column based on the flag value + * Flag 0/1: Use @colname (attribute) + * Flag 2: Use colname (element) + * Flag 3: Use colname|@colname (either) + */ +PG_FUNCTION_INFO_V1(tsql_openxml_get_colpattern); +Datum +tsql_openxml_get_colpattern(PG_FUNCTION_ARGS) +{ + char *xpath_expr; + int flag = PG_GETARG_INT32(1); + char *colname = text_to_cstring(PG_GETARG_TEXT_PP(0)); + + switch (flag) + { + case 0: + case 1: + /* For flags 0 and 1, use @colname */ + xpath_expr = psprintf("@%s", colname); + break; + case 2: + /* For flag 2, use colname */ + xpath_expr = pstrdup(colname); + break; + case 3: + /* For flag 3, use colname|@colname */ + xpath_expr = psprintf("%s|@%s", colname, colname); + break; + default: + /* Default to @colname for unknown flags */ + xpath_expr = psprintf("@%s", colname); + break; + } + + PG_RETURN_TEXT_P(cstring_to_text(xpath_expr)); } \ No newline at end of file diff --git a/contrib/babelfishpg_tsql/src/tsqlIface.cpp b/contrib/babelfishpg_tsql/src/tsqlIface.cpp index 395cf62ac9c..8a0a31e8c64 100644 --- a/contrib/babelfishpg_tsql/src/tsqlIface.cpp +++ b/contrib/babelfishpg_tsql/src/tsqlIface.cpp @@ -1253,6 +1253,16 @@ class tsqlCommonMutator : public TSqlParserBaseListener } } + void exitOpen_xml(TSqlParser::Open_xmlContext *ctx) override + { + if(ctx->table_name()) + { + rewritten_query_fragment.emplace(std::make_pair(ctx->table_name()->start->getStartIndex(), + std::make_pair("", "TABLE "))); + + } + } + void exitOpen_query(TSqlParser::Open_queryContext *ctx) override { TSqlParser::IdContext *linked_srv = ctx->linked_server; diff --git a/contrib/babelfishpg_tsql/src/tsqlUnsupportedFeatureHandler.cpp b/contrib/babelfishpg_tsql/src/tsqlUnsupportedFeatureHandler.cpp index 9eb05f076d2..9ad76628fc7 100644 --- a/contrib/babelfishpg_tsql/src/tsqlUnsupportedFeatureHandler.cpp +++ b/contrib/babelfishpg_tsql/src/tsqlUnsupportedFeatureHandler.cpp @@ -182,7 +182,7 @@ class TsqlUnsupportedFeatureHandlerImpl : public TsqlUnsupportedFeatureHandler antlrcpp::Any visitFunction_call(TSqlParser::Function_callContext *ctx) override; antlrcpp::Any visitAggregate_windowed_function(TSqlParser::Aggregate_windowed_functionContext *ctx) override; antlrcpp::Any visitRowset_function(TSqlParser::Rowset_functionContext *ctx) override { - if (!ctx->open_json() && (!pltsql_enable_linked_servers || !ctx->open_query())) { + if (!ctx->open_json() && (!pltsql_enable_linked_servers || !ctx->open_query()) && !ctx->open_xml()) { handle(INSTR_UNSUPPORTED_TSQL_ROWSET_FUNCTION, "rowset function", getLineAndPos(ctx)); } return visitChildren(ctx); diff --git a/test/JDBC/expected/openxml_with_clause-vu-verify.out b/test/JDBC/expected/openxml_with_clause-vu-verify.out new file mode 100644 index 00000000000..0076ea73bbe --- /dev/null +++ b/test/JDBC/expected/openxml_with_clause-vu-verify.out @@ -0,0 +1,282 @@ + +-- Test plan +-- When Colpattern is given for mapping +DECLARE @docHandle int; +DECLARE @xmlDocument nvarchar(1000); +SET @xmlDocument =N' + + + + + + + + + + + +'; +EXEC sp_xml_preparedocument @docHandle OUTPUT, @xmlDocument; +SELECT * +FROM OPENXML (@docHandle, '/ROOT/Customer/Order/OrderDetail/@ProductID') + WITH ( ProdID int '.', + Qty int '../@Quantity', + OID int '../../@OrderID'); +EXEC sp_xml_removedocument @docHandle; +GO +~~START~~ +int#!#int#!#int +11#!#12#!#10248 +42#!#10#!#10248 +72#!#3#!#10283 +~~END~~ + + + + +-- flag = 0 (default attribute centric) +DECLARE @DocHandle int; +DECLARE @XmlDocument nvarchar(1000); +SET @XmlDocument = N' + + + + + + + + + + + +'; +EXEC sp_xml_preparedocument @DocHandle OUTPUT, @XmlDocument; +SELECT * +FROM OPENXML (@DocHandle, '/ROOT/Customer',0) + WITH (CustomerID varchar(10) , + ContactName varchar(20)); +EXEC sp_xml_removedocument @DocHandle; +GO +~~START~~ +varchar#!#varchar +VINET#!#Paul Henriot +LILAS#!#Carlos Gonzalez +~~END~~ + + + + +-- flag = 1 (attribute centric) +DECLARE @DocHandle int; +DECLARE @XmlDocument nvarchar(1000); +SET @XmlDocument = N' + + + + + + + + + + + +'; +EXEC sp_xml_preparedocument @DocHandle OUTPUT, @XmlDocument; +SELECT * +FROM OPENXML (@DocHandle, '/ROOT/Customer',1) + WITH (CustomerID varchar(10) , + ContactName varchar(20)); +EXEC sp_xml_removedocument @DocHandle; +GO +~~START~~ +varchar#!#varchar +VINET#!#Paul Henriot +LILAS#!#Carlos Gonzalez +~~END~~ + + + + +-- flag = 2 (element centric) +DECLARE @XmlDocumentHandle int; +DECLARE @XmlDocument nvarchar(1000); +SET @XmlDocument = N' + + VINET + Paul Henriot + + + + + + + LILAS + Carlos Gonzalez + + + + +'; +EXEC sp_xml_preparedocument @XmlDocumentHandle OUTPUT, @XmlDocument; +SELECT * +FROM OPENXML (@XmlDocumentHandle, '/ROOT/Customer', 2) + WITH (CustomerID varchar(10), + ContactName varchar(20)); +EXEC sp_xml_removedocument @XmlDocumentHandle; +GO +~~START~~ +varchar#!#varchar +VINET#!#Paul Henriot +LILAS#!#Carlos Gonzalez +~~END~~ + + + + +-- flag = 3 (combines both) +DECLARE @DocHandle int; +DECLARE @XmlDocument nvarchar(1000); +SET @XmlDocument = N' + + + + + + + + LILAS + Carlos Gonzalez + + + + +'; +EXEC sp_xml_preparedocument @DocHandle OUTPUT, @XmlDocument; +SELECT * +FROM OPENXML (@DocHandle, '/ROOT/Customer',3) + WITH (customerid varchar(10), + contactname varchar(20)); +EXEC sp_xml_removedocument @DocHandle; +GO +~~START~~ +varchar#!#varchar +VINET#!#Paul Henriot +LILAS#!#Carlos Gonzalez +~~END~~ + + + + +-- flag = 8 +DECLARE @XmlDocumentHandle int; +DECLARE @XmlDocument nvarchar(1000); +SET @XmlDocument = N' + + VINET + Paul Henriot + + + + + + + + + + +'; +EXEC sp_xml_preparedocument @XmlDocumentHandle OUTPUT, @XmlDocument; +SELECT * +FROM OPENXML (@XmlDocumentHandle, '/ROOT/Customer',8) + WITH (CustomerID varchar(10), + ContactName varchar(20)); +EXEC sp_xml_removedocument @XmlDocumentHandle; +GO +~~START~~ +varchar#!#varchar +#!# +LILAS#!#Carlos Gonzalez +~~END~~ + + + + +-- default flag is 0 +DECLARE @idoc INT, @doc VARCHAR(1000); +SET @doc = N' + + VINET + Paul Henriot + + + + + + + + + + +'; +EXEC sp_xml_preparedocument @idoc OUTPUT, @doc; +SELECT * +FROM OPENXML (@idoc, '/ROOT/Customer') + WITH (CustomerID varchar(10), + ContactName varchar(20)); +EXEC sp_xml_removedocument @idoc; +GO +~~START~~ +varchar#!#varchar +#!# +LILAS#!#Carlos Gonzalez +~~END~~ + + + + + + +-- If tablename is given +CREATE TABLE T1(oid char(5), date datetime, amount float); +DECLARE @docHandle int; +DECLARE @XmlDocument varchar(1000); +SET @xmlDocument = N' + + + Customer was very + satisfied + + + + Important + + + +'; +EXEC sp_xml_preparedocument @docHandle OUTPUT, @xmlDocument; +SELECT * +FROM OPENXML (@docHandle, '/root/Customer/Order', 1) + WITH T1; +EXEC sp_xml_removedocument @docHandle; +GO +~~START~~ +char#!#datetime#!#float +O1 #!#1996-01-20 00:00:00.0#!#3.5 +O2 #!#1997-04-30 00:00:00.0#!#13.4 +O3 #!#1999-07-14 00:00:00.0#!#100.0 +O4 #!#1996-01-20 00:00:00.0#!#10000.0 +~~END~~ + +DROP TABLE T1; +GO diff --git a/test/JDBC/input/xml/openxml_with_clause-vu-verify.sql b/test/JDBC/input/xml/openxml_with_clause-vu-verify.sql new file mode 100644 index 00000000000..86065a04f0f --- /dev/null +++ b/test/JDBC/input/xml/openxml_with_clause-vu-verify.sql @@ -0,0 +1,231 @@ +-- Test plan + +-- When Colpattern is given for mapping +DECLARE @docHandle int; +DECLARE @xmlDocument nvarchar(1000); +SET @xmlDocument =N' + + + + + + + + + + + +'; +EXEC sp_xml_preparedocument @docHandle OUTPUT, @xmlDocument; +SELECT * +FROM OPENXML (@docHandle, '/ROOT/Customer/Order/OrderDetail/@ProductID') + WITH ( ProdID int '.', + Qty int '../@Quantity', + OID int '../../@OrderID'); +EXEC sp_xml_removedocument @docHandle; +GO + +-- flag = 0 (default attribute centric) +DECLARE @DocHandle int; +DECLARE @XmlDocument nvarchar(1000); +SET @XmlDocument = N' + + + + + + + + + + + +'; + +EXEC sp_xml_preparedocument @DocHandle OUTPUT, @XmlDocument; + +SELECT * +FROM OPENXML (@DocHandle, '/ROOT/Customer',0) + WITH (CustomerID varchar(10) , + ContactName varchar(20)); +EXEC sp_xml_removedocument @DocHandle; +GO + +-- flag = 1 (attribute centric) +DECLARE @DocHandle int; +DECLARE @XmlDocument nvarchar(1000); +SET @XmlDocument = N' + + + + + + + + + + + +'; + +EXEC sp_xml_preparedocument @DocHandle OUTPUT, @XmlDocument; + +SELECT * +FROM OPENXML (@DocHandle, '/ROOT/Customer',1) + WITH (CustomerID varchar(10) , + ContactName varchar(20)); +EXEC sp_xml_removedocument @DocHandle; +GO + +-- flag = 2 (element centric) +DECLARE @XmlDocumentHandle int; +DECLARE @XmlDocument nvarchar(1000); +SET @XmlDocument = N' + + VINET + Paul Henriot + + + + + + + LILAS + Carlos Gonzalez + + + + +'; + +EXEC sp_xml_preparedocument @XmlDocumentHandle OUTPUT, @XmlDocument; + +SELECT * +FROM OPENXML (@XmlDocumentHandle, '/ROOT/Customer', 2) + WITH (CustomerID varchar(10), + ContactName varchar(20)); +EXEC sp_xml_removedocument @XmlDocumentHandle; +GO + +-- flag = 3 (combines both) +DECLARE @DocHandle int; +DECLARE @XmlDocument nvarchar(1000); +SET @XmlDocument = N' + + + + + + + + LILAS + Carlos Gonzalez + + + + +'; + +EXEC sp_xml_preparedocument @DocHandle OUTPUT, @XmlDocument; + +SELECT * +FROM OPENXML (@DocHandle, '/ROOT/Customer',3) + WITH (customerid varchar(10), + contactname varchar(20)); +EXEC sp_xml_removedocument @DocHandle; +GO + +-- flag = 8 +DECLARE @XmlDocumentHandle int; +DECLARE @XmlDocument nvarchar(1000); +SET @XmlDocument = N' + + VINET + Paul Henriot + + + + + + + + + + +'; + +EXEC sp_xml_preparedocument @XmlDocumentHandle OUTPUT, @XmlDocument; + +SELECT * +FROM OPENXML (@XmlDocumentHandle, '/ROOT/Customer',8) + WITH (CustomerID varchar(10), + ContactName varchar(20)); +EXEC sp_xml_removedocument @XmlDocumentHandle; +GO + +-- default flag is 0 +DECLARE @idoc INT, @doc VARCHAR(1000); +SET @doc = N' + + VINET + Paul Henriot + + + + + + + + + + +'; + +EXEC sp_xml_preparedocument @idoc OUTPUT, @doc; + +SELECT * +FROM OPENXML (@idoc, '/ROOT/Customer') + WITH (CustomerID varchar(10), + ContactName varchar(20)); +EXEC sp_xml_removedocument @idoc; +GO + +-- If tablename is given +CREATE TABLE T1(oid char(5), date datetime, amount float); +DECLARE @docHandle int; +DECLARE @XmlDocument varchar(1000); + +SET @xmlDocument = N' + + + Customer was very + satisfied + + + + Important + + + +'; + +EXEC sp_xml_preparedocument @docHandle OUTPUT, @xmlDocument; + +SELECT * +FROM OPENXML (@docHandle, '/root/Customer/Order', 1) + WITH T1; + +EXEC sp_xml_removedocument @docHandle; +GO +DROP TABLE T1; +GO diff --git a/test/JDBC/upgrade/13_4/schedule b/test/JDBC/upgrade/13_4/schedule index fa84cfebc4c..5b39cca3c4f 100644 --- a/test/JDBC/upgrade/13_4/schedule +++ b/test/JDBC/upgrade/13_4/schedule @@ -262,6 +262,8 @@ BABEL-5031 test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument +openxml_with_clause +openxml_with_clause fixeddecimal_modulo BABEL-NUMERIC_EXPR test_conv_float_to_varchar_char_before_17_4 diff --git a/test/JDBC/upgrade/13_5/schedule b/test/JDBC/upgrade/13_5/schedule index 4f60f099a9d..e0d5c2993e7 100644 --- a/test/JDBC/upgrade/13_5/schedule +++ b/test/JDBC/upgrade/13_5/schedule @@ -315,6 +315,7 @@ BABEL-5031 test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument +openxml_with_clause fixeddecimal_modulo BABEL-NUMERIC_EXPR test_conv_float_to_varchar_char_before_17_4 diff --git a/test/JDBC/upgrade/13_6/schedule b/test/JDBC/upgrade/13_6/schedule index 88be1f34cec..52f89d79575 100644 --- a/test/JDBC/upgrade/13_6/schedule +++ b/test/JDBC/upgrade/13_6/schedule @@ -372,6 +372,7 @@ BABEL-5031 test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument +openxml_with_clause fixeddecimal_modulo BABEL-NUMERIC_EXPR test_conv_float_to_varchar_char_before_17_4 diff --git a/test/JDBC/upgrade/13_7/schedule b/test/JDBC/upgrade/13_7/schedule index e13039d836f..217e0ed0265 100644 --- a/test/JDBC/upgrade/13_7/schedule +++ b/test/JDBC/upgrade/13_7/schedule @@ -365,6 +365,7 @@ BABEL-5031 test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument +openxml_with_clause fixeddecimal_modulo BABEL-NUMERIC_EXPR test_conv_float_to_varchar_char_before_17_4 diff --git a/test/JDBC/upgrade/13_8/schedule b/test/JDBC/upgrade/13_8/schedule index e13039d836f..217e0ed0265 100644 --- a/test/JDBC/upgrade/13_8/schedule +++ b/test/JDBC/upgrade/13_8/schedule @@ -365,6 +365,7 @@ BABEL-5031 test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument +openxml_with_clause fixeddecimal_modulo BABEL-NUMERIC_EXPR test_conv_float_to_varchar_char_before_17_4 diff --git a/test/JDBC/upgrade/13_9/schedule b/test/JDBC/upgrade/13_9/schedule index 801d9f5e5ed..27c2613a8c9 100644 --- a/test/JDBC/upgrade/13_9/schedule +++ b/test/JDBC/upgrade/13_9/schedule @@ -370,6 +370,7 @@ BABEL-5031 test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument +openxml_with_clause fixeddecimal_modulo BABEL-NUMERIC_EXPR test_conv_float_to_varchar_char_before_17_4 diff --git a/test/JDBC/upgrade/14_10/schedule b/test/JDBC/upgrade/14_10/schedule index d903528486a..39532dc1fe6 100644 --- a/test/JDBC/upgrade/14_10/schedule +++ b/test/JDBC/upgrade/14_10/schedule @@ -483,6 +483,7 @@ BABEL-5031 test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument +openxml_with_clause fixeddecimal_modulo BABEL-NUMERIC_EXPR BABEL-5467 diff --git a/test/JDBC/upgrade/14_11/schedule b/test/JDBC/upgrade/14_11/schedule index 0309292e4be..4fbbe5fd4c3 100644 --- a/test/JDBC/upgrade/14_11/schedule +++ b/test/JDBC/upgrade/14_11/schedule @@ -481,6 +481,7 @@ BABEL-5031 test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument +openxml_with_clause fixeddecimal_modulo BABEL-NUMERIC_EXPR BABEL-5467 diff --git a/test/JDBC/upgrade/14_12/schedule b/test/JDBC/upgrade/14_12/schedule index dade8a0a33e..fc9f6de0a36 100644 --- a/test/JDBC/upgrade/14_12/schedule +++ b/test/JDBC/upgrade/14_12/schedule @@ -482,6 +482,7 @@ BABEL-5031 test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument +openxml_with_clause fixeddecimal_modulo BABEL-NUMERIC_EXPR BABEL-5467 diff --git a/test/JDBC/upgrade/14_13/schedule b/test/JDBC/upgrade/14_13/schedule index 3a050af3c3f..0e00d6c5890 100644 --- a/test/JDBC/upgrade/14_13/schedule +++ b/test/JDBC/upgrade/14_13/schedule @@ -482,6 +482,7 @@ BABEL-5031 test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument +openxml_with_clause fixeddecimal_modulo BABEL-NUMERIC_EXPR BABEL-5467 diff --git a/test/JDBC/upgrade/14_15/schedule b/test/JDBC/upgrade/14_15/schedule index 493d8097a8e..34b5c773036 100644 --- a/test/JDBC/upgrade/14_15/schedule +++ b/test/JDBC/upgrade/14_15/schedule @@ -478,6 +478,7 @@ BABEL-5031 test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument +openxml_with_clause fixeddecimal_modulo BABEL-NUMERIC_EXPR test_conv_float_to_varchar_char_before_17_4 diff --git a/test/JDBC/upgrade/14_17/schedule b/test/JDBC/upgrade/14_17/schedule index a2d81e0740a..d5326fef033 100644 --- a/test/JDBC/upgrade/14_17/schedule +++ b/test/JDBC/upgrade/14_17/schedule @@ -478,6 +478,7 @@ BABEL-5031 test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument +openxml_with_clause fixeddecimal_modulo BABEL-NUMERIC_EXPR BABEL-5467 diff --git a/test/JDBC/upgrade/14_3/schedule b/test/JDBC/upgrade/14_3/schedule index e3c3279f12c..e7236052cc7 100644 --- a/test/JDBC/upgrade/14_3/schedule +++ b/test/JDBC/upgrade/14_3/schedule @@ -401,6 +401,7 @@ BABEL-5031 test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument +openxml_with_clause fixeddecimal_modulo BABEL-NUMERIC_EXPR BABEL-5467 diff --git a/test/JDBC/upgrade/14_5/schedule b/test/JDBC/upgrade/14_5/schedule index 67239bf788b..d567cade367 100644 --- a/test/JDBC/upgrade/14_5/schedule +++ b/test/JDBC/upgrade/14_5/schedule @@ -413,6 +413,7 @@ BABEL-5031 test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument +openxml_with_clause fixeddecimal_modulo BABEL-NUMERIC_EXPR BABEL-5467 diff --git a/test/JDBC/upgrade/14_6/schedule b/test/JDBC/upgrade/14_6/schedule index 6474435b59c..df30d72e582 100644 --- a/test/JDBC/upgrade/14_6/schedule +++ b/test/JDBC/upgrade/14_6/schedule @@ -451,6 +451,7 @@ BABEL-5031 test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument +openxml_with_clause fixeddecimal_modulo BABEL-NUMERIC_EXPR BABEL-5467 diff --git a/test/JDBC/upgrade/14_7/schedule b/test/JDBC/upgrade/14_7/schedule index d7550773a80..e5b57a37a68 100644 --- a/test/JDBC/upgrade/14_7/schedule +++ b/test/JDBC/upgrade/14_7/schedule @@ -473,6 +473,7 @@ BABEL-5031 test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument +openxml_with_clause fixeddecimal_modulo BABEL-NUMERIC_EXPR BABEL-5467 diff --git a/test/JDBC/upgrade/14_8/schedule b/test/JDBC/upgrade/14_8/schedule index c455e9680c6..e0f9b12e95b 100644 --- a/test/JDBC/upgrade/14_8/schedule +++ b/test/JDBC/upgrade/14_8/schedule @@ -475,6 +475,7 @@ BABEL-5031 test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument +openxml_with_clause fixeddecimal_modulo BABEL-NUMERIC_EXPR BABEL-5467 diff --git a/test/JDBC/upgrade/14_9/schedule b/test/JDBC/upgrade/14_9/schedule index 9504a65a5b5..350f3b6b3c8 100644 --- a/test/JDBC/upgrade/14_9/schedule +++ b/test/JDBC/upgrade/14_9/schedule @@ -478,6 +478,7 @@ BABEL-5031 test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument +openxml_with_clause fixeddecimal_modulo BABEL-NUMERIC_EXPR BABEL-5467 diff --git a/test/JDBC/upgrade/15_1/schedule b/test/JDBC/upgrade/15_1/schedule index 12916303b78..86cd1142cfb 100644 --- a/test/JDBC/upgrade/15_1/schedule +++ b/test/JDBC/upgrade/15_1/schedule @@ -451,6 +451,7 @@ BABEL-5031 test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument +openxml_with_clause fixeddecimal_modulo BABEL-NUMERIC_EXPR BABEL-5467 diff --git a/test/JDBC/upgrade/15_10/schedule b/test/JDBC/upgrade/15_10/schedule index b6a405aa154..6b7a4855e65 100644 --- a/test/JDBC/upgrade/15_10/schedule +++ b/test/JDBC/upgrade/15_10/schedule @@ -569,6 +569,7 @@ BABEL-5031 test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument +openxml_with_clause fixeddecimal_modulo BABEL-NUMERIC_EXPR BABEL-5467 diff --git a/test/JDBC/upgrade/15_12/schedule b/test/JDBC/upgrade/15_12/schedule index 9365dcf4daa..7dfa04ddc18 100644 --- a/test/JDBC/upgrade/15_12/schedule +++ b/test/JDBC/upgrade/15_12/schedule @@ -569,6 +569,7 @@ BABEL-5031 test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument +openxml_with_clause fixeddecimal_modulo BABEL-NUMERIC_EXPR BABEL-5467 diff --git a/test/JDBC/upgrade/15_2/schedule b/test/JDBC/upgrade/15_2/schedule index 62e179fd52c..e2bb43c3eb2 100644 --- a/test/JDBC/upgrade/15_2/schedule +++ b/test/JDBC/upgrade/15_2/schedule @@ -487,6 +487,7 @@ BABEL-5031 test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument +openxml_with_clause fixeddecimal_modulo BABEL-NUMERIC_EXPR BABEL-5467 diff --git a/test/JDBC/upgrade/15_3/schedule b/test/JDBC/upgrade/15_3/schedule index ac70aba4e8e..c680f95a8a7 100644 --- a/test/JDBC/upgrade/15_3/schedule +++ b/test/JDBC/upgrade/15_3/schedule @@ -507,6 +507,7 @@ BABEL-5031 test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument +openxml_with_clause fixeddecimal_modulo BABEL-NUMERIC_EXPR BABEL-5467 diff --git a/test/JDBC/upgrade/15_4/schedule b/test/JDBC/upgrade/15_4/schedule index 26be5abb660..3a789e5e688 100644 --- a/test/JDBC/upgrade/15_4/schedule +++ b/test/JDBC/upgrade/15_4/schedule @@ -520,6 +520,7 @@ BABEL-5031 test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument +openxml_with_clause fixeddecimal_modulo BABEL-NUMERIC_EXPR BABEL-5467 diff --git a/test/JDBC/upgrade/15_5/schedule b/test/JDBC/upgrade/15_5/schedule index f544c0595ad..d750802bda7 100644 --- a/test/JDBC/upgrade/15_5/schedule +++ b/test/JDBC/upgrade/15_5/schedule @@ -554,6 +554,7 @@ BABEL-5031 test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument +openxml_with_clause fixeddecimal_modulo BABEL-NUMERIC_EXPR test_conv_float_to_varchar_char_before_17_4 diff --git a/test/JDBC/upgrade/15_6/schedule b/test/JDBC/upgrade/15_6/schedule index 9989782024a..93596d1ad05 100644 --- a/test/JDBC/upgrade/15_6/schedule +++ b/test/JDBC/upgrade/15_6/schedule @@ -569,6 +569,7 @@ BABEL-5031 test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument +openxml_with_clause fixeddecimal_modulo BABEL-NUMERIC_EXPR BABEL-5467 diff --git a/test/JDBC/upgrade/15_7/schedule b/test/JDBC/upgrade/15_7/schedule index 83acbc8a54b..6dc053328c9 100644 --- a/test/JDBC/upgrade/15_7/schedule +++ b/test/JDBC/upgrade/15_7/schedule @@ -577,6 +577,7 @@ BABEL-5031 test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument +openxml_with_clause fixeddecimal_modulo BABEL-NUMERIC_EXPR BABEL-5467 diff --git a/test/JDBC/upgrade/15_8/schedule b/test/JDBC/upgrade/15_8/schedule index 348f9c59205..16d09b828de 100644 --- a/test/JDBC/upgrade/15_8/schedule +++ b/test/JDBC/upgrade/15_8/schedule @@ -569,6 +569,7 @@ BABEL-5031 test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument +openxml_with_clause fixeddecimal_modulo BABEL-NUMERIC_EXPR BABEL-5467 diff --git a/test/JDBC/upgrade/16_1/schedule b/test/JDBC/upgrade/16_1/schedule index fbe934343a8..c872d6dab59 100644 --- a/test/JDBC/upgrade/16_1/schedule +++ b/test/JDBC/upgrade/16_1/schedule @@ -562,6 +562,7 @@ BABEL-5031 test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument +openxml_with_clause fixeddecimal_modulo BABEL-NUMERIC_EXPR test_conv_float_to_varchar_char_before_17_4 diff --git a/test/JDBC/upgrade/16_10/schedule b/test/JDBC/upgrade/16_10/schedule index 9c973388d73..9589f623af3 100644 --- a/test/JDBC/upgrade/16_10/schedule +++ b/test/JDBC/upgrade/16_10/schedule @@ -604,6 +604,7 @@ BABEL-5031 test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument +openxml_with_clause fixeddecimal_modulo BABEL-NUMERIC_EXPR test_conv_float_to_varchar_char diff --git a/test/JDBC/upgrade/16_2/schedule b/test/JDBC/upgrade/16_2/schedule index c4e3dff6761..95b203e9782 100644 --- a/test/JDBC/upgrade/16_2/schedule +++ b/test/JDBC/upgrade/16_2/schedule @@ -578,6 +578,7 @@ BABEL-5031 test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument +openxml_with_clause fixeddecimal_modulo BABEL-NUMERIC_EXPR test_conv_float_to_varchar_char_before_17_4 diff --git a/test/JDBC/upgrade/16_3/schedule b/test/JDBC/upgrade/16_3/schedule index 3c77c5f6eff..786d29e8f02 100644 --- a/test/JDBC/upgrade/16_3/schedule +++ b/test/JDBC/upgrade/16_3/schedule @@ -581,6 +581,7 @@ BABEL-5031 test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument +openxml_with_clause fixeddecimal_modulo BABEL-NUMERIC_EXPR test_conv_float_to_varchar_char_before_17_4 diff --git a/test/JDBC/upgrade/16_4/schedule b/test/JDBC/upgrade/16_4/schedule index 352437cd8cf..227c44669c5 100644 --- a/test/JDBC/upgrade/16_4/schedule +++ b/test/JDBC/upgrade/16_4/schedule @@ -595,6 +595,7 @@ BABEL-5031 test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument +openxml_with_clause fixeddecimal_modulo BABEL-NUMERIC_EXPR test_conv_float_to_varchar_char_before_17_4 diff --git a/test/JDBC/upgrade/16_6/schedule b/test/JDBC/upgrade/16_6/schedule index 3b31cea553e..972af40cfc6 100644 --- a/test/JDBC/upgrade/16_6/schedule +++ b/test/JDBC/upgrade/16_6/schedule @@ -598,6 +598,7 @@ BABEL-5031 test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument +openxml_with_clause fixeddecimal_modulo BABEL-NUMERIC_EXPR test_conv_float_to_varchar_char_before_17_4 diff --git a/test/JDBC/upgrade/16_9/schedule b/test/JDBC/upgrade/16_9/schedule index 12968d1d283..a6c01728bb0 100644 --- a/test/JDBC/upgrade/16_9/schedule +++ b/test/JDBC/upgrade/16_9/schedule @@ -604,6 +604,7 @@ BABEL-5031 test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument +openxml_with_clause fixeddecimal_modulo BABEL-NUMERIC_EXPR test_conv_float_to_varchar_char diff --git a/test/JDBC/upgrade/latest/schedule b/test/JDBC/upgrade/latest/schedule index 7cb30b9c637..cbe41e1a5d5 100644 --- a/test/JDBC/upgrade/latest/schedule +++ b/test/JDBC/upgrade/latest/schedule @@ -605,6 +605,7 @@ BABEL-5031 test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument +openxml_with_clause fixeddecimal_modulo BABEL-NUMERIC_EXPR test_conv_float_to_varchar_char From 58234309510789589dc6050c535fdc637027d7e7 Mon Sep 17 00:00:00 2001 From: Harsh Dubey Date: Tue, 10 Jun 2025 19:07:34 +0000 Subject: [PATCH 05/40] fixing the failures Signed-off-by: Harsh Dubey --- contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-rule.y | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-rule.y b/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-rule.y index a45f27c4069..4a03fc57637 100644 --- a/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-rule.y +++ b/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-rule.y @@ -1806,7 +1806,7 @@ openxml_expr: OPENXML '(' a_expr ',' a_expr ')' opt_alias_clause n->tsql_docid = $3; n->rowexpr = $5; n->alias = $7; - n->columns = TsqlMakeOpenxmlColList(); + n->columns = NIL; n->location = @1; $$ = (Node *) n; } @@ -1816,7 +1816,7 @@ openxml_expr: OPENXML '(' a_expr ',' a_expr ')' opt_alias_clause n->tsql_docid = $3; n->rowexpr = $5; n->tsql_flag = $7; - n->columns = TsqlMakeOpenxmlColList(); + n->columns = NIL; n->alias = $9; n->location = @1; $$ = (Node *) n; From b3fd2ae91247be84b2c1a6ad3dcc18cf84ddbd95 Mon Sep 17 00:00:00 2001 From: Harsh Dubey Date: Wed, 11 Jun 2025 13:49:07 +0000 Subject: [PATCH 06/40] Fixed the files to add the same changes of stored procedures Signed-off-by: Harsh Dubey --- .../babelfishpg_tsql--5.1.0--5.2.0.sql | 30 ------------------- .../babelfishpg_tsql--5.2.0--5.3.0.sql | 30 +++++++++++++++++++ test/JDBC/upgrade/14_17/schedule | 3 -- test/JDBC/upgrade/14_18/schedule | 3 ++ test/JDBC/upgrade/15_12/schedule | 3 -- test/JDBC/upgrade/15_13/schedule | 3 ++ test/JDBC/upgrade/16_10/schedule | 3 -- 7 files changed, 36 insertions(+), 39 deletions(-) diff --git a/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--5.1.0--5.2.0.sql b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--5.1.0--5.2.0.sql index cd09fd92766..dad8aa405a2 100644 --- a/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--5.1.0--5.2.0.sql +++ b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--5.1.0--5.2.0.sql @@ -1553,36 +1553,6 @@ GRANT SELECT ON sys.dm_os_sys_info TO PUBLIC; -- Please have this be one of the last statements executed in this upgrade script. DROP PROCEDURE sys.babelfish_drop_deprecated_object(varchar, varchar, varchar); -CREATE OR REPLACE PROCEDURE sys.sp_xml_preparedocument( - INOUT "@hdoc" INTEGER, - IN "@xmltext" sys.VARCHAR DEFAULT NULL, - IN "@xpath_namespaces" sys.VARCHAR DEFAULT NULL -) -AS 'babelfishpg_tsql', 'sp_xml_preparedocument' -LANGUAGE C; -GRANT EXECUTE ON PROCEDURE sys.sp_xml_preparedocument( - INOUT INTEGER, IN sys.varchar, IN sys.varchar -) TO PUBLIC; - -CREATE OR REPLACE PROCEDURE sys.sp_xml_removedocument( - IN "@hdoc" INTEGER -) -AS 'babelfishpg_tsql', 'sp_xml_removedocument' -LANGUAGE C; -GRANT EXECUTE ON PROCEDURE sys.sp_xml_removedocument( - IN INTEGER -) TO PUBLIC; - -CREATE OR REPLACE FUNCTION sys.tsql_openxml_get_xmldoc(int) -RETURNS xml -AS 'babelfishpg_tsql', 'tsql_openxml_get_xmldoc' -LANGUAGE C STRICT; - -CREATE OR REPLACE FUNCTION sys.tsql_openxml_get_colpattern(text,int) -RETURNS sys.nvarchar -AS 'babelfishpg_tsql', 'tsql_openxml_get_colpattern' -LANGUAGE C STRICT; - -- After upgrade, always run analyze for all babelfish catalogs. CALL sys.analyze_babelfish_catalogs(); -- Reset search_path to not affect any subsequent scripts diff --git a/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--5.2.0--5.3.0.sql b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--5.2.0--5.3.0.sql index 699db7566fc..f56c83e96b3 100644 --- a/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--5.2.0--5.3.0.sql +++ b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--5.2.0--5.3.0.sql @@ -468,6 +468,36 @@ WHERE sch.nspname = t.typnamespace::regnamespace::name -- Please have this be one of the last statements executed in this upgrade script. DROP PROCEDURE sys.babelfish_drop_deprecated_object(varchar, varchar, varchar); +CREATE OR REPLACE PROCEDURE sys.sp_xml_preparedocument( + INOUT "@hdoc" INTEGER, + IN "@xmltext" sys.VARCHAR DEFAULT NULL, + IN "@xpath_namespaces" sys.VARCHAR DEFAULT NULL +) +AS 'babelfishpg_tsql', 'sp_xml_preparedocument' +LANGUAGE C; +GRANT EXECUTE ON PROCEDURE sys.sp_xml_preparedocument( + INOUT INTEGER, IN sys.varchar, IN sys.varchar +) TO PUBLIC; + +CREATE OR REPLACE PROCEDURE sys.sp_xml_removedocument( + IN "@hdoc" INTEGER +) +AS 'babelfishpg_tsql', 'sp_xml_removedocument' +LANGUAGE C; +GRANT EXECUTE ON PROCEDURE sys.sp_xml_removedocument( + IN INTEGER +) TO PUBLIC; + +CREATE OR REPLACE FUNCTION sys.tsql_openxml_get_xmldoc(int) +RETURNS xml +AS 'babelfishpg_tsql', 'tsql_openxml_get_xmldoc' +LANGUAGE C STRICT; + +CREATE OR REPLACE FUNCTION sys.tsql_openxml_get_colpattern(text,int) +RETURNS sys.nvarchar +AS 'babelfishpg_tsql', 'tsql_openxml_get_colpattern' +LANGUAGE C STRICT; + -- After upgrade, always run analyze for all babelfish catalogs. CALL sys.analyze_babelfish_catalogs(); -- Reset search_path to not affect any subsequent scripts diff --git a/test/JDBC/upgrade/14_17/schedule b/test/JDBC/upgrade/14_17/schedule index d5326fef033..dd7966ec2e9 100644 --- a/test/JDBC/upgrade/14_17/schedule +++ b/test/JDBC/upgrade/14_17/schedule @@ -476,9 +476,6 @@ test_conv_string_to_smalldatetime test_conv_string_to_time-before-17_4 BABEL-5031 test_conv_money_to_varchar -sp_xml_preparedocument -sp_xml_removedocument -openxml_with_clause fixeddecimal_modulo BABEL-NUMERIC_EXPR BABEL-5467 diff --git a/test/JDBC/upgrade/14_18/schedule b/test/JDBC/upgrade/14_18/schedule index 4c7808d1e8d..609591499bf 100644 --- a/test/JDBC/upgrade/14_18/schedule +++ b/test/JDBC/upgrade/14_18/schedule @@ -476,6 +476,9 @@ test_conv_string_to_smalldatetime test_conv_string_to_time-before-17_4 BABEL-5031 test_conv_money_to_varchar +sp_xml_preparedocument +sp_xml_removedocument +openxml_with_clause fixeddecimal_modulo BABEL-NUMERIC_EXPR BABEL-5467 diff --git a/test/JDBC/upgrade/15_12/schedule b/test/JDBC/upgrade/15_12/schedule index 7dfa04ddc18..003edb0c15e 100644 --- a/test/JDBC/upgrade/15_12/schedule +++ b/test/JDBC/upgrade/15_12/schedule @@ -567,9 +567,6 @@ test_conv_string_to_smalldatetime test_conv_string_to_time-before-17_4 BABEL-5031 test_conv_money_to_varchar -sp_xml_preparedocument -sp_xml_removedocument -openxml_with_clause fixeddecimal_modulo BABEL-NUMERIC_EXPR BABEL-5467 diff --git a/test/JDBC/upgrade/15_13/schedule b/test/JDBC/upgrade/15_13/schedule index 59fe2ad6899..919fb5d949d 100644 --- a/test/JDBC/upgrade/15_13/schedule +++ b/test/JDBC/upgrade/15_13/schedule @@ -567,6 +567,9 @@ test_conv_string_to_smalldatetime test_conv_string_to_time-before-17_4 BABEL-5031 test_conv_money_to_varchar +sp_xml_preparedocument +sp_xml_removedocument +openxml_with_clause fixeddecimal_modulo BABEL-NUMERIC_EXPR BABEL-5467 diff --git a/test/JDBC/upgrade/16_10/schedule b/test/JDBC/upgrade/16_10/schedule index 9589f623af3..401e413257d 100644 --- a/test/JDBC/upgrade/16_10/schedule +++ b/test/JDBC/upgrade/16_10/schedule @@ -602,9 +602,6 @@ test_conv_string_to_time-before-17_4 db_owner BABEL-5031 test_conv_money_to_varchar -sp_xml_preparedocument -sp_xml_removedocument -openxml_with_clause fixeddecimal_modulo BABEL-NUMERIC_EXPR test_conv_float_to_varchar_char From b543c5d01a3370c4b6f8685915a3bf1c66f3be6b Mon Sep 17 00:00:00 2001 From: Harsh Dubey Date: Fri, 13 Jun 2025 08:56:30 +0000 Subject: [PATCH 07/40] Added the function name in output file of expected dependency & corrected indentations Signed-off-by: Harsh Dubey --- .../babelfishpg_tsql/sql/sys_functions.sql | 4 +- .../src/backend_parser/gram-tsql-rule.y | 35 ++-- contrib/babelfishpg_tsql/src/hooks.c | 173 +++++++++-------- contrib/babelfishpg_tsql/src/pltsql.h | 5 +- contrib/babelfishpg_tsql/src/procedures.c | 179 +++++++++--------- .../openxml_with_clause-vu-verify.out | 6 +- .../xml/openxml_with_clause-vu-verify.sql | 6 +- .../expected_dependency.out | 2 + 8 files changed, 209 insertions(+), 201 deletions(-) diff --git a/contrib/babelfishpg_tsql/sql/sys_functions.sql b/contrib/babelfishpg_tsql/sql/sys_functions.sql index b9ae1f60da7..6874e89c86e 100644 --- a/contrib/babelfishpg_tsql/sql/sys_functions.sql +++ b/contrib/babelfishpg_tsql/sql/sys_functions.sql @@ -4001,12 +4001,12 @@ AS 'babelfishpg_tsql', 'tsql_openjson_with' LANGUAGE C STRICT IMMUTABLE PARALLEL CREATE OR REPLACE FUNCTION sys.tsql_openxml_get_xmldoc(int) RETURNS xml AS 'babelfishpg_tsql', 'tsql_openxml_get_xmldoc' -LANGUAGE C STRICT; +LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE; CREATE OR REPLACE FUNCTION sys.tsql_openxml_get_colpattern(text,int) RETURNS sys.nvarchar AS 'babelfishpg_tsql', 'tsql_openxml_get_colpattern' -LANGUAGE C STRICT; +LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE; CREATE OR REPLACE FUNCTION sys.sp_datatype_info_helper( IN odbcVer smallint, diff --git a/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-rule.y b/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-rule.y index 4a03fc57637..78f2486410a 100644 --- a/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-rule.y +++ b/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-rule.y @@ -1877,32 +1877,31 @@ openxml_column_list: openxml_column_el { $$ = list_make1($1); openxml_column_el: ColId Typename - { - RangeTableFuncCol *fc = makeNode(RangeTableFuncCol); + { + RangeTableFuncCol *fc = makeNode(RangeTableFuncCol); - fc->colname = $1; - fc->typeName = $2; - /* Set a default XPath expression based on column name */ + fc->colname = $1; + fc->typeName = $2; + /* Set a default XPath expression based on column name */ /* fc->colexpr = (Node *) makeStringConst(psprintf("@%s", $1), @1); */ - /* fc->colexpr = makeStringConst($1, @1); */ + /* fc->colexpr = makeStringConst($1, @1); */ fc->colexpr = NULL; - fc->location = @1; + fc->location = @1; - $$ = (Node *) fc; - } + $$ = (Node *) fc; + } | ColId Typename Sconst - { - RangeTableFuncCol *fc = makeNode(RangeTableFuncCol); - fc->colname = $1; - fc->typeName = $2; - fc->colexpr = (Node *) makeStringConst($3, @1); - fc->location = @1; + { + RangeTableFuncCol *fc = makeNode(RangeTableFuncCol); + fc->colname = $1; + fc->typeName = $2; + fc->colexpr = (Node *) makeStringConst($3, @1); + fc->location = @1; - $$ = (Node *) fc; - } + $$ = (Node *) fc; + } ; - openjson_expr: OPENJSON '(' a_expr ')' opt_alias_clause { RangeFunction *n = makeNode(RangeFunction); diff --git a/contrib/babelfishpg_tsql/src/hooks.c b/contrib/babelfishpg_tsql/src/hooks.c index 663bfba8afb..9a54c92d2f1 100644 --- a/contrib/babelfishpg_tsql/src/hooks.c +++ b/contrib/babelfishpg_tsql/src/hooks.c @@ -6526,84 +6526,95 @@ pltsql_exprTypmod(Plan *plan, Node *expr) } /* - * fetch_table_schema - Get column definitions from an existing table + * fetch_table_schema - Extract column metadata from a table for OPENXML processing * - * This function retrieves column information from a specified table and - * creates RangeTableFuncCol nodes for each column. These are then used - * in the OPENXML WITH table_name syntax to define the output columns. + * This function retrieves column definitions from an existing table and transforms + * them into RangeTableFuncCol nodes with appropriate XPath expressions. It handles + * column name, type information, and creates expressions using tsql_openxml_get_colpattern function. + * + * Parameters: + * relation - The table to extract schema information from + * flag - The OPENXML flag parameter that controls XML mapping behavior + * + * Returns: + * List of RangeTableFuncCol nodes representing the table's columns */ - static List * fetch_table_schema(RangeVar *relation, Node *flag) { - List *columns = NIL; - - if (relation != NULL) - { - Relation rel; - TupleDesc tupdesc; - int i; - - /* Open the relation to get its schema */ - rel = relation_openrv(relation, AccessShareLock); - - if (rel == NULL) - { - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_TABLE), - errmsg("table \"%s\" does not exist", - relation->relname))); - } - - /* Get the tuple descriptor which contains column information */ - tupdesc = RelationGetDescr(rel); - - /* Create RangeTableFuncCol nodes from the table's columns */ - for (i = 0; i < tupdesc->natts; i++) - { - Form_pg_attribute att = TupleDescAttr(tupdesc, i); - RangeTableFuncCol *fc; - char *colname; - - /* Skip system columns and dropped columns */ - if (att->attisdropped || att->attnum < 0) - continue; - - colname = NameStr(att->attname); - - /* Create a column definition */ - fc = makeNode(RangeTableFuncCol); - fc->colname = pstrdup(colname); - - /* Create a TypeName node for the column type */ - fc->typeName = makeTypeNameFromOid(att->atttypid, att->atttypmod); - - /* Set the column expression to the generated XPath */ - fc->colexpr = (Node *) makeFuncCall(list_make2(makeString("sys"), makeString("tsql_openxml_get_colpattern")), - list_make2(makeStringConst(colname, -1), flag), - COERCE_EXPLICIT_CALL, - -1); - fc->coldefexpr = NULL; - fc->location = -1; - - columns = lappend(columns, fc); - } - - /* Close the relation */ - relation_close(rel, AccessShareLock); - } + List *columns = NIL; + + if (relation != NULL) + { + Relation rel; + TupleDesc tupdesc; + int i; + + /* Open the relation to get its schema */ + rel = relation_openrv(relation, AccessShareLock); + + if (rel == NULL) + { + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_TABLE), + errmsg("table \"%s\" does not exist", + relation->relname))); + } + + /* Get the tuple descriptor which contains column information */ + tupdesc = RelationGetDescr(rel); + + /* Create RangeTableFuncCol nodes from the table's columns */ + for (i = 0; i < tupdesc->natts; i++) + { + Form_pg_attribute att = TupleDescAttr(tupdesc, i); + RangeTableFuncCol *fc; + char *colname; + + /* Skip dropped and generated columns */ + if (att->attisdropped || att->attgenerated) + continue; + + colname = NameStr(att->attname); + + /* Create a column definition */ + fc = makeNode(RangeTableFuncCol); + fc->colname = pstrdup(colname); + + /* Create a TypeName node for the column type */ + fc->typeName = makeTypeNameFromOid(att->atttypid, att->atttypmod); + + /* Set the column expression to the generated XPath */ + fc->colexpr = (Node *) makeFuncCall(list_make2(makeString("sys"), makeString("tsql_openxml_get_colpattern")), list_make2(makeStringConst(colname, -1), flag), COERCE_EXPLICIT_CALL, -1); + fc->coldefexpr = NULL; + fc->location = -1; + + columns = lappend(columns, fc); + } + + relation_close(rel, AccessShareLock); + } return columns; } +/* + * transformOpenxml_expr - Process OPENXML expressions for T-SQL compatibility + * + * This function handles the transformation of OPENXML expressions by either: + * 1. Using a referenced table's schema to generate appropriate column definitions, or + * 2. Processing explicitly provided columns by generating XPath expressions based on + * column names and the specified flag parameter. + * + * The function ensures each column has a proper col expression using the tsql_openxml_get_colpattern function. + */ static void transformOpenxml_expr(ParseState *pstate, Openxml_expr *expr) { - /* If a table reference was provided, get the columns from that table */ + /* If a table reference is provided, get the columns from that table */ if (expr->table_ref != NULL) { - /* Fetch the table schema and generate column definitions with appropriate XPath expressions */ expr->columns = fetch_table_schema(expr->table_ref, expr->tsql_flag); } else if (expr->columns != NIL) @@ -6617,27 +6628,30 @@ transformOpenxml_expr(ParseState *pstate, Openxml_expr *expr) /* If no column expression is provided, generate one based on the flag */ if (fc->colexpr == NULL) { - /* - * To get original column name, utilize location of ColumnDef and query - * string. - */ + /* To get original column name, utilize location of ColumnDef and query string. For colexpr, we need orignal name of columns (no downcase or uppercase) */ const char *column_name_start = pstate->p_sourcetext + fc->location; char *original_name = extract_identifier(column_name_start, NULL); - fc->colexpr = (Node *) makeFuncCall(list_make2(makeString("sys"), makeString("tsql_openxml_get_colpattern")), - list_make2(makeStringConst(original_name, -1), expr->tsql_flag), - COERCE_EXPLICIT_CALL, - -1); + /* Create an XPath expression for the column using tsql_openxml_get_colpattern. This builds a function call to generate the appropriate XPath pattern + * based on the column name and the OPENXML flag parameter + */ + fc->colexpr = (Node *) makeFuncCall(list_make2(makeString("sys"), makeString("tsql_openxml_get_colpattern")), list_make2(makeStringConst(original_name, -1), expr->tsql_flag), COERCE_EXPLICIT_CALL, -1); } } } } +/* + * bbf_transformFromClauseItem - Transform T-SQL OPENXML expressions in FROM clauses + * + * This hook function handles the transformation of T-SQL specific OPENXML expressions + * in FROM clauses into PostgreSQL's RangeTableFunc structures. It converts the + * OPENXML syntax into appropriate function calls to extract and process XML data. + * The function only processes nodes when in T-SQL dialect mode. + */ static Node * -bbf_transformFromClauseItem(ParseState *pstate, Node *n, - ParseNamespaceItem **top_nsitem, - List **namespace) +bbf_transformFromClauseItem(ParseState *pstate, Node *n, ParseNamespaceItem **top_nsitem, List **namespace) { if (sql_dialect != SQL_DIALECT_TSQL) return NULL; @@ -6651,11 +6665,12 @@ bbf_transformFromClauseItem(ParseState *pstate, Node *n, Openxml_expr *expr = (Openxml_expr *) n; transformOpenxml_expr(pstate, expr); - rtf->docexpr = (Node *) makeFuncCall(list_make2(makeString("sys"), makeString("tsql_openxml_get_xmldoc")), - list_make1(expr->tsql_docid), - COERCE_EXPLICIT_CALL, - -1); - // rtf->docexpr = (Node *) tsql_openxml_get_xmldoc(expr->tsql_docid); + + /* Set the document expression to retrieve the XML document using the document handle. This creates a function call to tsql_openxml_get_xmldoc + * which retrieves the previously prepared XML document based on the document ID from sp_xml_preparedocument. + */ + rtf->docexpr = (Node *) makeFuncCall(list_make2(makeString("sys"), makeString("tsql_openxml_get_xmldoc")), list_make1(expr->tsql_docid), COERCE_EXPLICIT_CALL, -1); + rtf->rowexpr = expr->rowexpr; rtf->columns = expr->columns; rtf->alias = expr->alias; diff --git a/contrib/babelfishpg_tsql/src/pltsql.h b/contrib/babelfishpg_tsql/src/pltsql.h index e58edbed7f4..96372262a07 100644 --- a/contrib/babelfishpg_tsql/src/pltsql.h +++ b/contrib/babelfishpg_tsql/src/pltsql.h @@ -1810,9 +1810,6 @@ typedef struct PLtsql_protocol_plugin char **tvp_type_name, char **tvp_type_schema_name); int32_t (*get_tds_numeric_get_typmod) (Numeric num); - - - int32 (*get_numeric_typmod_from_exp) (Plan *plan, Node *expr, bool *found); /* Session level GUCs */ bool quoted_identifier; bool arithabort; @@ -2372,4 +2369,4 @@ extern char *tsql_format_type_extended(Oid type_oid, int32 typemod, bits16 flags extern const char *shipped_objects_not_in_sys_db[NUM_DB_OBJECTS][2]; -#endif /* PLTSQL_H */ +#endif /* PLTSQL_H */ \ No newline at end of file diff --git a/contrib/babelfishpg_tsql/src/procedures.c b/contrib/babelfishpg_tsql/src/procedures.c index ea760d48d3e..782a402d167 100644 --- a/contrib/babelfishpg_tsql/src/procedures.c +++ b/contrib/babelfishpg_tsql/src/procedures.c @@ -85,6 +85,8 @@ PG_FUNCTION_INFO_V1(sp_reset_connection_internal); PG_FUNCTION_INFO_V1(sp_renamedb_internal); PG_FUNCTION_INFO_V1(sp_xml_preparedocument); PG_FUNCTION_INFO_V1(sp_xml_removedocument); +PG_FUNCTION_INFO_V1(tsql_openxml_get_colpattern); +PG_FUNCTION_INFO_V1(tsql_openxml_get_xmldoc); extern void delete_cached_batch(int handle); extern InlineCodeBlockArgs *create_args(int numargs); @@ -4940,27 +4942,24 @@ sp_xml_removedocument(PG_FUNCTION_ARGS) PG_RETURN_VOID(); } -PG_FUNCTION_INFO_V1(tsql_openxml_get_xmldoc); - /* * Function to retrieve XML document from temporary table using document ID */ Datum tsql_openxml_get_xmldoc(PG_FUNCTION_ARGS) { - int32 document_id = PG_GETARG_INT32(0); - Relation relation; - ScanKeyData skey[1]; - TableScanDesc scan; - HeapTuple tuple; - bool found = false; - Datum result = (Datum) 0; - bool isnull = true; - EphemeralNamedRelation enr = NULL; - - - /* Check if the temporary table exists */ - if (xml_handle_temp_table_name != NULL) + int32 document_id = PG_GETARG_INT32(0); + Relation relation; + ScanKeyData skey[1]; + TableScanDesc scan; + HeapTuple tuple; + bool found = false; + Datum result = (Datum) 0; + bool isnull = true; + EphemeralNamedRelation enr = NULL; + + /* Check if the temporary table exists */ + if (xml_handle_temp_table_name != NULL) { enr = get_ENR(currentQueryEnv, xml_handle_temp_table_name, true); if (enr) @@ -4969,91 +4968,87 @@ tsql_openxml_get_xmldoc(PG_FUNCTION_ARGS) } } + if (!OidIsValid(enr->md.reliddesc)) + { + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("XML document with ID %d not found", document_id))); + } - if (!OidIsValid(enr->md.reliddesc)) - { - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("XML document with ID %d not found", document_id))); - } - - /* Open the relation */ - relation = relation_open(enr->md.reliddesc, AccessShareLock); - - /* Set up the scan key */ - ScanKeyInit(&skey[0], - 1, /* Column number */ - BTEqualStrategyNumber, F_INT4EQ, - Int32GetDatum(document_id)); - - /* Start the scan */ - scan = table_beginscan_catalog(relation, 1, skey); - tuple = heap_getnext(scan, ForwardScanDirection); - - /* Find the document */ - if (HeapTupleIsValid(tuple)) - { - /* Get the XML document from column 6 (doc) */ - result = heap_getattr(tuple, 6, RelationGetDescr(relation), &isnull); - - if (!isnull) - { - /* Make a copy of the value */ - result = datumCopy(result, false, -1); - found = true; - } - } - - /* Clean up */ - table_endscan(scan); - relation_close(relation, AccessShareLock); - - /* If we found the document, return it */ - if (found) - PG_RETURN_DATUM(result); - - /* Otherwise, throw an error */ - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("XML document with ID %d not found", document_id))); - - PG_RETURN_NULL(); /* Never reached */ + ScanKeyInit(&skey[0], + 1, /* Column number */ + BTEqualStrategyNumber, F_INT4EQ, + Int32GetDatum(document_id)); + + scan = table_beginscan_catalog(relation, 1, skey); + tuple = heap_getnext(scan, ForwardScanDirection); + + if (HeapTupleIsValid(tuple)) + { + /* Get the XML document from column 6 (doc) */ + result = heap_getattr(tuple, 6, RelationGetDescr(relation), &isnull); + + if (!isnull) + { + /* Make a copy of the value */ + result = datumCopy(result, false, -1); + found = true; + } + } + + table_endscan(scan); + relation_close(relation, AccessShareLock); + + /* If we found the document, return it */ + if (found) + PG_RETURN_DATUM(result); + + /* If we get here , we did not find the document */ + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("XML document with ID %d not found", document_id))); + + PG_RETURN_NULL(); } /* - * Generate XPath expression for a column based on the flag value - * Flag 0/1: Use @colname (attribute) - * Flag 2: Use colname (element) - * Flag 3: Use colname|@colname (either) + * tsql_openxml_get_colpattern - Generate XPath expressions for OPENXML columns + * + * This function generates the appropriate XPath expression for a column based on + * the OPENXML flag value. The flag determines whether to access XML data as + * attributes, elements, or either. + * flag - Controls the XPath pattern generation: + * 0,1: Use attribute access (@colname) + * 2: Use element access (colname) + * 3: Try both element and attribute (colname|@colname) */ -PG_FUNCTION_INFO_V1(tsql_openxml_get_colpattern); Datum tsql_openxml_get_colpattern(PG_FUNCTION_ARGS) { - char *xpath_expr; + char *xpath_expr; int flag = PG_GETARG_INT32(1); char *colname = text_to_cstring(PG_GETARG_TEXT_PP(0)); - - switch (flag) - { - case 0: - case 1: - /* For flags 0 and 1, use @colname */ - xpath_expr = psprintf("@%s", colname); - break; - case 2: - /* For flag 2, use colname */ - xpath_expr = pstrdup(colname); - break; - case 3: - /* For flag 3, use colname|@colname */ - xpath_expr = psprintf("%s|@%s", colname, colname); - break; - default: - /* Default to @colname for unknown flags */ - xpath_expr = psprintf("@%s", colname); - break; - } - - PG_RETURN_TEXT_P(cstring_to_text(xpath_expr)); + + switch (flag) + { + case 0: + case 1: + /* For flags 0 and 1, use @colname */ + xpath_expr = psprintf("@%s", colname); + break; + case 2: + /* For flag 2, use colname */ + xpath_expr = pstrdup(colname); + break; + case 3: + /* For flag 3, use colname|@colname */ + xpath_expr = psprintf("%s|@%s", colname, colname); + break; + default: + /* Default to @colname for unknown flags */ + xpath_expr = psprintf("@%s", colname); + break; + } + + PG_RETURN_TEXT_P(cstring_to_text(xpath_expr)); } \ No newline at end of file diff --git a/test/JDBC/expected/openxml_with_clause-vu-verify.out b/test/JDBC/expected/openxml_with_clause-vu-verify.out index 0076ea73bbe..2b3a8cda3bd 100644 --- a/test/JDBC/expected/openxml_with_clause-vu-verify.out +++ b/test/JDBC/expected/openxml_with_clause-vu-verify.out @@ -247,7 +247,7 @@ LILAS#!#Carlos Gonzalez -- If tablename is given -CREATE TABLE T1(oid char(5), date datetime, amount float); +CREATE TABLE test_openxml_table(oid char(5), date datetime, amount float); DECLARE @docHandle int; DECLARE @XmlDocument varchar(1000); SET @xmlDocument = N' @@ -267,7 +267,7 @@ SET @xmlDocument = N' EXEC sp_xml_preparedocument @docHandle OUTPUT, @xmlDocument; SELECT * FROM OPENXML (@docHandle, '/root/Customer/Order', 1) - WITH T1; + WITH test_openxml_table; EXEC sp_xml_removedocument @docHandle; GO ~~START~~ @@ -278,5 +278,5 @@ O3 #!#1999-07-14 00:00:00.0#!#100.0 O4 #!#1996-01-20 00:00:00.0#!#10000.0 ~~END~~ -DROP TABLE T1; +DROP TABLE test_openxml_table; GO diff --git a/test/JDBC/input/xml/openxml_with_clause-vu-verify.sql b/test/JDBC/input/xml/openxml_with_clause-vu-verify.sql index 86065a04f0f..ea818249754 100644 --- a/test/JDBC/input/xml/openxml_with_clause-vu-verify.sql +++ b/test/JDBC/input/xml/openxml_with_clause-vu-verify.sql @@ -200,7 +200,7 @@ EXEC sp_xml_removedocument @idoc; GO -- If tablename is given -CREATE TABLE T1(oid char(5), date datetime, amount float); +CREATE TABLE test_openxml_table(oid char(5), date datetime, amount float); DECLARE @docHandle int; DECLARE @XmlDocument varchar(1000); @@ -223,9 +223,9 @@ EXEC sp_xml_preparedocument @docHandle OUTPUT, @xmlDocument; SELECT * FROM OPENXML (@docHandle, '/root/Customer/Order', 1) - WITH T1; + WITH test_openxml_table; EXEC sp_xml_removedocument @docHandle; GO -DROP TABLE T1; +DROP TABLE test_openxml_table; GO diff --git a/test/python/expected/upgrade_validation/expected_dependency.out b/test/python/expected/upgrade_validation/expected_dependency.out index 7ba19da2288..07b85a5beb3 100644 --- a/test/python/expected/upgrade_validation/expected_dependency.out +++ b/test/python/expected/upgrade_validation/expected_dependency.out @@ -722,6 +722,8 @@ Function sys.tsql_get_constraintdef(oid) Function sys.tsql_get_expr(text,oid) Function sys.tsql_get_functiondef(oid) Function sys.tsql_get_returntypmodvalue(oid) +Function sys.tsql_openxml_get_colpattern(text,integer) +Function sys.tsql_openxml_get_xmldoc(integer) Function sys.tsql_query_to_json_ffunc(internal) Function sys.tsql_query_to_json_sfunc(internal,anyelement,integer,boolean,boolean,text) Function sys.tsql_query_to_xml_ffunc(internal) From 3c1714a86911f274bdb5b88f9b2cc94ee6ee119c Mon Sep 17 00:00:00 2001 From: Harsh Dubey Date: Sun, 15 Jun 2025 11:57:19 +0000 Subject: [PATCH 08/40] Fixed the output file of expected create Signed-off-by: Harsh Dubey --- .../expected/sql_validation_framework/expected_create.out | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/python/expected/sql_validation_framework/expected_create.out b/test/python/expected/sql_validation_framework/expected_create.out index 72f464cfc6b..efae640d193 100644 --- a/test/python/expected/sql_validation_framework/expected_create.out +++ b/test/python/expected/sql_validation_framework/expected_create.out @@ -53,6 +53,8 @@ Could not find tests for function sys.suser_name_internal Could not find tests for function sys.systypes_precision_helper Could not find tests for function sys.timezone Could not find tests for function sys.tsql_get_returntypmodvalue +Could not find upgrade tests for function sys.tsql_openxml_get_colpattern +Could not find upgrade tests for function sys.tsql_openxml_get_xmldoc Could not find tests for function sys.tsql_query_to_json_ffunc Could not find tests for function sys.tsql_query_to_json_sfunc Could not find tests for function sys.tsql_query_to_xml_ffunc @@ -162,6 +164,8 @@ Could not find upgrade tests for function sys.systypes_precision_helper Could not find upgrade tests for function sys.timezone Could not find upgrade tests for function sys.tsql_get_functiondef Could not find upgrade tests for function sys.tsql_get_returntypmodvalue +Could not find upgrade tests for function sys.tsql_openxml_get_colpattern +Could not find upgrade tests for function sys.tsql_openxml_get_xmldoc Could not find upgrade tests for function sys.tsql_query_to_json_ffunc Could not find upgrade tests for function sys.tsql_query_to_json_sfunc Could not find upgrade tests for function sys.tsql_query_to_xml_ffunc From 1dcd1a4c28cc5dcbf2c2b92c63f64961b36fd93e Mon Sep 17 00:00:00 2001 From: Harsh Dubey Date: Mon, 16 Jun 2025 05:52:53 +0000 Subject: [PATCH 09/40] Fixed the output file of expected_create Signed-off-by: Harsh Dubey --- .../expected/sql_validation_framework/expected_create.out | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/python/expected/sql_validation_framework/expected_create.out b/test/python/expected/sql_validation_framework/expected_create.out index efae640d193..b31902267f6 100644 --- a/test/python/expected/sql_validation_framework/expected_create.out +++ b/test/python/expected/sql_validation_framework/expected_create.out @@ -53,8 +53,8 @@ Could not find tests for function sys.suser_name_internal Could not find tests for function sys.systypes_precision_helper Could not find tests for function sys.timezone Could not find tests for function sys.tsql_get_returntypmodvalue -Could not find upgrade tests for function sys.tsql_openxml_get_colpattern -Could not find upgrade tests for function sys.tsql_openxml_get_xmldoc +Could not find tests for function sys.tsql_openxml_get_colpattern +Could not find tests for function sys.tsql_openxml_get_xmldoc Could not find tests for function sys.tsql_query_to_json_ffunc Could not find tests for function sys.tsql_query_to_json_sfunc Could not find tests for function sys.tsql_query_to_xml_ffunc From a6a63fd18c43d431acb1de93d1051fa178636af0 Mon Sep 17 00:00:00 2001 From: Harsh Dubey Date: Thu, 19 Jun 2025 12:14:42 +0000 Subject: [PATCH 10/40] New approach for openxml Signed-off-by: Harsh Dubey --- .../src/backend_parser/gram-tsql-rule.y | 130 +++++----- contrib/babelfishpg_tsql/src/hooks.c | 229 +++++++++++++----- 2 files changed, 228 insertions(+), 131 deletions(-) diff --git a/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-rule.y b/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-rule.y index 78f2486410a..83fd4fa45b3 100644 --- a/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-rule.y +++ b/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-rule.y @@ -1800,76 +1800,76 @@ table_ref: relation_expr tsql_table_hint_expr } ; -openxml_expr: OPENXML '(' a_expr ',' a_expr ')' opt_alias_clause +openxml_expr: OPENXML '(' Iconst ',' a_expr ')' opt_alias_clause { - Openxml_expr *n = makeNode(Openxml_expr); - n->tsql_docid = $3; + RangeTableFunc *n = makeNode(RangeTableFunc); + n->docexpr = NULL; n->rowexpr = $5; - n->alias = $7; - n->columns = NIL; n->location = @1; + /* Default flag is 0 when not specified */ + n->namespaces = list_make2(makeIntConst($3, @1), makeIntConst(0, @1)); + n->columns = NIL; + n->alias = $7; $$ = (Node *) n; } - | OPENXML '(' a_expr ',' a_expr ',' a_expr ')' opt_alias_clause + | OPENXML '(' Iconst ',' a_expr ',' Iconst ')' opt_alias_clause { - Openxml_expr *n = makeNode(Openxml_expr); - n->tsql_docid = $3; + RangeTableFunc *n = makeNode(RangeTableFunc); + n->docexpr = NULL; n->rowexpr = $5; - n->tsql_flag = $7; - n->columns = NIL; - n->alias = $9; n->location = @1; + n->namespaces = list_make2(makeIntConst($3, @1), makeIntConst($7, @1)); + n->columns = NIL; + n->alias = $9; $$ = (Node *) n; } - | OPENXML '(' a_expr ',' a_expr ')' WITH_table TABLE qualified_name opt_alias_clause + | OPENXML '(' Iconst ',' a_expr ')' WITH_table TABLE qualified_name opt_alias_clause { - Openxml_expr *n = makeNode(Openxml_expr); - n->tsql_docid = $3; + RangeTableFunc *n = makeNode(RangeTableFunc); + n->docexpr = NULL; n->rowexpr = $5; - n->table_ref = $9; - n->alias = $10; n->location = @1; - /* Default flag is 0 when not specified */ - n->tsql_flag = makeIntConst(0, -1); + /* Default flag is 0 when not specified */ + n->namespaces = list_make2(makeIntConst($3, @1), makeIntConst(0, @1)); + n->columns = list_make1($9); + n->alias = $10; $$ = (Node *) n; } - | OPENXML '(' a_expr ',' a_expr ',' a_expr ')' WITH_table TABLE qualified_name opt_alias_clause + | OPENXML '(' Iconst ',' a_expr ',' Iconst ')' WITH_table TABLE qualified_name opt_alias_clause { - Openxml_expr *n = makeNode(Openxml_expr); - n->tsql_docid = $3; - n->rowexpr = $5; - n->tsql_flag = $7; - n->table_ref = $11; - n->alias = $12; - n->location = @1; - $$ = (Node *) n; + RangeTableFunc *n = makeNode(RangeTableFunc); + n->docexpr = NULL; + n->rowexpr = $5; + n->location = @1; + n->namespaces = list_make2(makeIntConst($3, @1), makeIntConst($7, @1)); + n->columns = list_make1($11); + n->alias = $12; + $$ = (Node *) n; } - | OPENXML '(' a_expr ',' a_expr ')' WITH_paren '(' openxml_column_list ')' opt_alias_clause + | OPENXML '(' Iconst ',' a_expr ')' WITH_paren '(' openxml_column_list ')' opt_alias_clause { - Openxml_expr *n = makeNode(Openxml_expr); - n->tsql_docid = $3; + RangeTableFunc *n = makeNode(RangeTableFunc); + n->docexpr = NULL; n->rowexpr = $5; - n->columns = $9; - n->alias = $11; - n->table_ref = NULL; n->location = @1; - /* Default flag is 0 when not specified */ - n->tsql_flag = makeIntConst(0, -1); + /* Default flag is 0 when not specified */ + n->columns = $9; + n->namespaces = list_make2(makeIntConst($3, @1), makeIntConst(0, @1)); + n->alias = $11; $$ = (Node *) n; } - | OPENXML '(' a_expr ',' a_expr ',' a_expr ')' WITH_paren '(' openxml_column_list ')' opt_alias_clause + | OPENXML '(' Iconst ',' a_expr ',' Iconst ')' WITH_paren '(' openxml_column_list ')' opt_alias_clause { - Openxml_expr *n = makeNode(Openxml_expr); - n->tsql_docid = $3; - n->rowexpr = $5; - n->tsql_flag = $7; - n->columns = $11; - n->alias = $13; - n->table_ref = NULL; - n->location = @1; - $$ = (Node *) n; + RangeTableFunc *n = makeNode(RangeTableFunc); + n->docexpr = NULL; + n->rowexpr = $5; + n->columns = $11; + n->location = @1; + n->namespaces = list_make2(makeIntConst($3, @1), makeIntConst($7, @1)); + n->alias = $13; + $$ = (Node *) n; } - ; + ; openxml_column_list: openxml_column_el { $$ = list_make1($1); } | openxml_column_list ',' openxml_column_el { $$ = lappend($1, $3); } @@ -1877,29 +1877,29 @@ openxml_column_list: openxml_column_el { $$ = list_make1($1); openxml_column_el: ColId Typename - { - RangeTableFuncCol *fc = makeNode(RangeTableFuncCol); + { + RangeTableFuncCol *fc = makeNode(RangeTableFuncCol); - fc->colname = $1; - fc->typeName = $2; - /* Set a default XPath expression based on column name */ - /* fc->colexpr = (Node *) makeStringConst(psprintf("@%s", $1), @1); */ - /* fc->colexpr = makeStringConst($1, @1); */ - fc->colexpr = NULL; - fc->location = @1; + fc->colname = $1; + fc->typeName = $2; + fc->colexpr = NULL; + fc->coldefexpr = NULL; + fc->location = @1; - $$ = (Node *) fc; - } + $$ = (Node *) fc; + } | ColId Typename Sconst - { - RangeTableFuncCol *fc = makeNode(RangeTableFuncCol); - fc->colname = $1; - fc->typeName = $2; - fc->colexpr = (Node *) makeStringConst($3, @1); - fc->location = @1; + { + RangeTableFuncCol *fc = makeNode(RangeTableFuncCol); - $$ = (Node *) fc; - } + fc->colname = $1; + fc->typeName = $2; + fc->colexpr = (Node *) makeStringConst($3, @1); + fc->coldefexpr = NULL; + fc->location = @1; + + $$ = (Node *) fc; + } ; openjson_expr: OPENJSON '(' a_expr ')' opt_alias_clause diff --git a/contrib/babelfishpg_tsql/src/hooks.c b/contrib/babelfishpg_tsql/src/hooks.c index db28e3bc49a..ebe88943aac 100644 --- a/contrib/babelfishpg_tsql/src/hooks.c +++ b/contrib/babelfishpg_tsql/src/hooks.c @@ -250,7 +250,7 @@ static char* pltsql_get_object_identity_event_trigger(ObjectAddress *addr); static const char *remove_db_name_in_schema(const char *schema_name, const char *object_type); static int32 pltsql_exprTypmod(Plan *plan, Node *expr); static Oid get_domain_typmodin(Type typ); -static Node* bbf_transformFromClauseItem(ParseState *pstate, Node *n, ParseNamespaceItem **top_nsitem, List **namespace); +static void pre_transform_openxml_columns(ParseState *pstate, RangeTableFunc *rtf); /*************************************************** * Temp Table Related Declarations + Hooks @@ -304,7 +304,7 @@ static match_pltsql_func_call_hook_type prev_match_pltsql_func_call_hook = NULL; static insert_pltsql_function_defaults_hook_type prev_insert_pltsql_function_defaults_hook = NULL; static replace_pltsql_function_defaults_hook_type prev_replace_pltsql_function_defaults_hook = NULL; static exprTypmod_hook_type prev_exprTypmod_hook = NULL; -static transformFromClauseItem_hook_type prev_transformFromClauseItem_hook = NULL; +static pre_transform_openxml_columns_hook_type prev_pre_transform_openxml_columns_hook = NULL; static print_pltsql_function_arguments_hook_type prev_print_pltsql_function_arguments_hook = NULL; static planner_hook_type prev_planner_hook = NULL; static transform_check_constraint_expr_hook_type prev_transform_check_constraint_expr_hook = NULL; @@ -468,8 +468,8 @@ InstallExtendedHooks(void) prev_exprTypmod_hook = exprTypmod_hook; exprTypmod_hook = pltsql_exprTypmod; - prev_transformFromClauseItem_hook = transformFromClauseItem_hook; - transformFromClauseItem_hook = bbf_transformFromClauseItem; + prev_pre_transform_openxml_columns_hook = pre_transform_openxml_columns_hook; + pre_transform_openxml_columns_hook = pre_transform_openxml_columns; prev_print_pltsql_function_arguments_hook = print_pltsql_function_arguments_hook; print_pltsql_function_arguments_hook = print_pltsql_function_arguments; @@ -636,7 +636,7 @@ UninstallExtendedHooks(void) insert_pltsql_function_defaults_hook = prev_insert_pltsql_function_defaults_hook; replace_pltsql_function_defaults_hook = prev_replace_pltsql_function_defaults_hook; exprTypmod_hook = prev_exprTypmod_hook; - transformFromClauseItem_hook = prev_transformFromClauseItem_hook; + pre_transform_openxml_columns_hook = prev_pre_transform_openxml_columns_hook; print_pltsql_function_arguments_hook = prev_print_pltsql_function_arguments_hook; planner_hook = prev_planner_hook; transform_check_constraint_expr_hook = prev_transform_check_constraint_expr_hook; @@ -6615,39 +6615,39 @@ fetch_table_schema(RangeVar *relation, Node *flag) * * The function ensures each column has a proper col expression using the tsql_openxml_get_colpattern function. */ -static void -transformOpenxml_expr(ParseState *pstate, Openxml_expr *expr) -{ - - /* If a table reference is provided, get the columns from that table */ - if (expr->table_ref != NULL) - { - expr->columns = fetch_table_schema(expr->table_ref, expr->tsql_flag); - } - else if (expr->columns != NIL) - { - /* Handle case where columns are provided but no table name */ - ListCell *lc; - foreach(lc, expr->columns) - { - RangeTableFuncCol *fc = (RangeTableFuncCol *) lfirst(lc); +// static void +// transformOpenxml_expr(ParseState *pstate, Openxml_expr *expr) +// { + +// /* If a table reference is provided, get the columns from that table */ +// if (expr->table_ref != NULL) +// { +// expr->columns = fetch_table_schema(expr->table_ref, expr->tsql_flag); +// } +// else if (expr->columns != NIL) +// { +// /* Handle case where columns are provided but no table name */ +// ListCell *lc; +// foreach(lc, expr->columns) +// { +// RangeTableFuncCol *fc = (RangeTableFuncCol *) lfirst(lc); - /* If no column expression is provided, generate one based on the flag */ - if (fc->colexpr == NULL) - { - /* To get original column name, utilize location of ColumnDef and query string. For colexpr, we need orignal name of columns (no downcase or uppercase) */ - const char *column_name_start = pstate->p_sourcetext + fc->location; - char *original_name = extract_identifier(column_name_start, NULL); - - /* Create an XPath expression for the column using tsql_openxml_get_colpattern. This builds a function call to generate the appropriate XPath pattern - * based on the column name and the OPENXML flag parameter - */ - fc->colexpr = (Node *) makeFuncCall(list_make2(makeString("sys"), makeString("tsql_openxml_get_colpattern")), list_make2(makeStringConst(original_name, -1), expr->tsql_flag), COERCE_EXPLICIT_CALL, -1); - } - } - } - -} +// /* If no column expression is provided, generate one based on the flag */ +// if (fc->colexpr == NULL) +// { +// /* To get original column name, utilize location of ColumnDef and query string. For colexpr, we need orignal name of columns (no downcase or uppercase) */ +// const char *column_name_start = pstate->p_sourcetext + fc->location; +// char *original_name = extract_identifier(column_name_start, NULL); + +// /* Create an XPath expression for the column using tsql_openxml_get_colpattern. This builds a function call to generate the appropriate XPath pattern +// * based on the column name and the OPENXML flag parameter +// */ +// fc->colexpr = (Node *) makeFuncCall(list_make2(makeString("sys"), makeString("tsql_openxml_get_colpattern")), list_make2(makeStringConst(original_name, -1), expr->tsql_flag), COERCE_EXPLICIT_CALL, -1); +// } +// } +// } + +// } /* * bbf_transformFromClauseItem - Transform T-SQL OPENXML expressions in FROM clauses @@ -6657,43 +6657,140 @@ transformOpenxml_expr(ParseState *pstate, Openxml_expr *expr) * OPENXML syntax into appropriate function calls to extract and process XML data. * The function only processes nodes when in T-SQL dialect mode. */ -static Node * -bbf_transformFromClauseItem(ParseState *pstate, Node *n, ParseNamespaceItem **top_nsitem, List **namespace) -{ - if (sql_dialect != SQL_DIALECT_TSQL) - return NULL; +// static Node * +// bbf_transformFromClauseItem(ParseState *pstate, Node *n, ParseNamespaceItem **top_nsitem, List **namespace) +// { +// if (sql_dialect != SQL_DIALECT_TSQL) +// return NULL; + +// if (IsA(n, Openxml_expr)) +// { +// /* table function is like a plain relation */ +// RangeTblRef *rtr; +// ParseNamespaceItem *nsitem; +// RangeTableFunc *rtf = makeNode(RangeTableFunc); +// Openxml_expr *expr = (Openxml_expr *) n; + +// transformOpenxml_expr(pstate, expr); + +// /* Set the document expression to retrieve the XML document using the document handle. This creates a function call to tsql_openxml_get_xmldoc +// * which retrieves the previously prepared XML document based on the document ID from sp_xml_preparedocument. +// */ +// rtf->docexpr = (Node *) makeFuncCall(list_make2(makeString("sys"), makeString("tsql_openxml_get_xmldoc")), list_make1(expr->tsql_docid), COERCE_EXPLICIT_CALL, -1); + +// rtf->rowexpr = expr->rowexpr; +// rtf->columns = expr->columns; +// rtf->alias = expr->alias; +// rtf->location = expr->location; +// rtf->namespaces = NIL; + +// nsitem = bbf_transformRangeTableFunc(pstate, rtf); + +// *top_nsitem = nsitem; +// *namespace = list_make1(nsitem); +// rtr = makeNode(RangeTblRef); +// rtr->rtindex = nsitem->p_rtindex; +// return (Node *) rtr; +// } + +// return NULL; +// } - if (IsA(n, Openxml_expr)) +/* + * tsql_openxml_get_colpattern - Generate XPath expressions for OPENXML columns + * + * This function generates the appropriate XPath expression for a column based on + * the OPENXML flag value. The flag determines whether to access XML data as + * attributes, elements, or either. + * flag - Controls the XPath pattern generation: + * 0,1: Use attribute access (@colname) + * 2: Use element access (colname) + * 3: Try both element and attribute (colname|@colname) + */ +Datum +tsql_openxml_get_colpattern(PG_FUNCTION_ARGS) +{ + char *xpath_expr; + int flag = PG_GETARG_INT32(1); + char *colname = text_to_cstring(PG_GETARG_TEXT_PP(0)); + + switch (flag) { - /* table function is like a plain relation */ - RangeTblRef *rtr; - ParseNamespaceItem *nsitem; - RangeTableFunc *rtf = makeNode(RangeTableFunc); - Openxml_expr *expr = (Openxml_expr *) n; + case 0: + case 1: + /* For flags 0 and 1, use @colname */ + xpath_expr = psprintf("@%s", colname); + break; + case 2: + /* For flag 2, use colname */ + xpath_expr = pstrdup(colname); + break; + case 3: + /* For flag 3, use colname|@colname */ + xpath_expr = psprintf("%s|@%s", colname, colname); + break; + default: + /* Default to @colname for unknown flags */ + xpath_expr = psprintf("@%s", colname); + break; + } + + PG_RETURN_TEXT_P(cstring_to_text(xpath_expr)); +} - transformOpenxml_expr(pstate, expr); +static void +pre_transform_openxml_columns(ParseState *pstate, RangeTableFunc *rtf) +{ + Node *tsql_docid_node; + Node *tsql_flag; + RangeVar *table_ref; - /* Set the document expression to retrieve the XML document using the document handle. This creates a function call to tsql_openxml_get_xmldoc - * which retrieves the previously prepared XML document based on the document ID from sp_xml_preparedocument. - */ - rtf->docexpr = (Node *) makeFuncCall(list_make2(makeString("sys"), makeString("tsql_openxml_get_xmldoc")), list_make1(expr->tsql_docid), COERCE_EXPLICIT_CALL, -1); + if (sql_dialect != SQL_DIALECT_TSQL) + return; - rtf->rowexpr = expr->rowexpr; - rtf->columns = expr->columns; - rtf->alias = expr->alias; - rtf->location = expr->location; - rtf->namespaces = NIL; + tsql_docid_node = linitial(rtf->namespaces); + tsql_flag = lsecond(rtf->namespaces); - nsitem = bbf_transformRangeTableFunc(pstate, rtf); + /* Set the document expression to retrieve the XML document using the document handle. This creates a function call to tsql_openxml_get_xmldoc + * which retrieves the previously prepared XML document based on the document ID from sp_xml_preparedocument. + */ + rtf->docexpr = (Node *) makeFuncCall(list_make2(makeString("sys"), makeString("tsql_openxml_get_xmldoc")), list_make1(tsql_docid_node), COERCE_EXPLICIT_CALL, -1); - *top_nsitem = nsitem; - *namespace = list_make1(nsitem); - rtr = makeNode(RangeTblRef); - rtr->rtindex = nsitem->p_rtindex; - return (Node *) rtr; - } + if (rtf->columns != NIL) + { + Node *first_col = linitial(rtf->columns); - return NULL; + if (IsA(first_col, RangeVar)) + { + table_ref = (RangeVar *) first_col; + /* Fetch the table schema and generate column definitions with appropriate XPath expressions */ + rtf->columns = fetch_table_schema(table_ref, tsql_flag); + } + else + { + ListCell *lc; + + foreach(lc, rtf->columns) + { + RangeTableFuncCol *fc = (RangeTableFuncCol *) lfirst(lc); + + /* If no column expression is provided, generate one based on the flag */ + if(fc->colexpr == NULL && tsql_flag != NULL) + { + /* To get original column name, utilize location of ColumnDef and query string. For colexpr, we need orignal name of columns (no downcase or uppercase) */ + const char *column_name_start = pstate->p_sourcetext + fc->location; + char *original_name = extract_identifier(column_name_start, NULL); + + if (original_name == NULL) + original_name = fc->colname; + /* Create an XPath expression for the column using tsql_openxml_get_colpattern. This builds a function call to generate the appropriate XPath pattern + * based on the column name and the OPENXML flag parameter + */ + fc->colexpr = (Node *) makeFuncCall(list_make2(makeString("sys"), makeString("tsql_openxml_get_colpattern")), list_make2(makeStringConst(original_name, -1), tsql_flag), COERCE_EXPLICIT_CALL, -1); + } + } + } + } } /* From 5bb932d2d87eb1cc1ed3c30a168ea86c37991b5c Mon Sep 17 00:00:00 2001 From: Harsh Dubey Date: Thu, 19 Jun 2025 13:24:26 +0000 Subject: [PATCH 11/40] Fixed new approach of openxxml Signed-off-by: Harsh Dubey --- .../src/backend_parser/gram-tsql-rule.y | 24 +++++------ contrib/babelfishpg_tsql/src/hooks.c | 43 +------------------ 2 files changed, 14 insertions(+), 53 deletions(-) diff --git a/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-rule.y b/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-rule.y index 83fd4fa45b3..620759bf8ee 100644 --- a/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-rule.y +++ b/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-rule.y @@ -1800,53 +1800,53 @@ table_ref: relation_expr tsql_table_hint_expr } ; -openxml_expr: OPENXML '(' Iconst ',' a_expr ')' opt_alias_clause +openxml_expr: OPENXML '(' a_expr ',' a_expr ')' opt_alias_clause { RangeTableFunc *n = makeNode(RangeTableFunc); n->docexpr = NULL; n->rowexpr = $5; n->location = @1; /* Default flag is 0 when not specified */ - n->namespaces = list_make2(makeIntConst($3, @1), makeIntConst(0, @1)); + n->namespaces = list_make2((Node*)$3, makeIntConst(0, @1)); n->columns = NIL; n->alias = $7; $$ = (Node *) n; } - | OPENXML '(' Iconst ',' a_expr ',' Iconst ')' opt_alias_clause + | OPENXML '(' a_expr ',' a_expr ',' a_expr ')' opt_alias_clause { RangeTableFunc *n = makeNode(RangeTableFunc); n->docexpr = NULL; n->rowexpr = $5; n->location = @1; - n->namespaces = list_make2(makeIntConst($3, @1), makeIntConst($7, @1)); + n->namespaces = list_make2((Node *)$3, (Node *)$7); n->columns = NIL; n->alias = $9; $$ = (Node *) n; } - | OPENXML '(' Iconst ',' a_expr ')' WITH_table TABLE qualified_name opt_alias_clause + | OPENXML '(' a_expr ',' a_expr ')' WITH_table TABLE qualified_name opt_alias_clause { RangeTableFunc *n = makeNode(RangeTableFunc); n->docexpr = NULL; n->rowexpr = $5; n->location = @1; /* Default flag is 0 when not specified */ - n->namespaces = list_make2(makeIntConst($3, @1), makeIntConst(0, @1)); + n->namespaces = list_make2((Node *)$3, makeIntConst(0, @1)); n->columns = list_make1($9); n->alias = $10; $$ = (Node *) n; } - | OPENXML '(' Iconst ',' a_expr ',' Iconst ')' WITH_table TABLE qualified_name opt_alias_clause + | OPENXML '(' a_expr ',' a_expr ',' a_expr ')' WITH_table TABLE qualified_name opt_alias_clause { RangeTableFunc *n = makeNode(RangeTableFunc); n->docexpr = NULL; n->rowexpr = $5; n->location = @1; - n->namespaces = list_make2(makeIntConst($3, @1), makeIntConst($7, @1)); + n->namespaces = list_make2((Node *)$3, (Node *)$7); n->columns = list_make1($11); n->alias = $12; $$ = (Node *) n; } - | OPENXML '(' Iconst ',' a_expr ')' WITH_paren '(' openxml_column_list ')' opt_alias_clause + | OPENXML '(' a_expr ',' a_expr ')' WITH_paren '(' openxml_column_list ')' opt_alias_clause { RangeTableFunc *n = makeNode(RangeTableFunc); n->docexpr = NULL; @@ -1854,18 +1854,18 @@ openxml_expr: OPENXML '(' Iconst ',' a_expr ')' opt_alias_clause n->location = @1; /* Default flag is 0 when not specified */ n->columns = $9; - n->namespaces = list_make2(makeIntConst($3, @1), makeIntConst(0, @1)); + n->namespaces = list_make2((Node *)$3, makeIntConst(0, @1)); n->alias = $11; $$ = (Node *) n; } - | OPENXML '(' Iconst ',' a_expr ',' Iconst ')' WITH_paren '(' openxml_column_list ')' opt_alias_clause + | OPENXML '(' a_expr ',' a_expr ',' a_expr ')' WITH_paren '(' openxml_column_list ')' opt_alias_clause { RangeTableFunc *n = makeNode(RangeTableFunc); n->docexpr = NULL; n->rowexpr = $5; n->columns = $11; n->location = @1; - n->namespaces = list_make2(makeIntConst($3, @1), makeIntConst($7, @1)); + n->namespaces = list_make2((Node *)$3, (Node *)$7); n->alias = $13; $$ = (Node *) n; } diff --git a/contrib/babelfishpg_tsql/src/hooks.c b/contrib/babelfishpg_tsql/src/hooks.c index ebe88943aac..0e35a9de21e 100644 --- a/contrib/babelfishpg_tsql/src/hooks.c +++ b/contrib/babelfishpg_tsql/src/hooks.c @@ -6696,47 +6696,6 @@ fetch_table_schema(RangeVar *relation, Node *flag) // return NULL; // } -/* - * tsql_openxml_get_colpattern - Generate XPath expressions for OPENXML columns - * - * This function generates the appropriate XPath expression for a column based on - * the OPENXML flag value. The flag determines whether to access XML data as - * attributes, elements, or either. - * flag - Controls the XPath pattern generation: - * 0,1: Use attribute access (@colname) - * 2: Use element access (colname) - * 3: Try both element and attribute (colname|@colname) - */ -Datum -tsql_openxml_get_colpattern(PG_FUNCTION_ARGS) -{ - char *xpath_expr; - int flag = PG_GETARG_INT32(1); - char *colname = text_to_cstring(PG_GETARG_TEXT_PP(0)); - - switch (flag) - { - case 0: - case 1: - /* For flags 0 and 1, use @colname */ - xpath_expr = psprintf("@%s", colname); - break; - case 2: - /* For flag 2, use colname */ - xpath_expr = pstrdup(colname); - break; - case 3: - /* For flag 3, use colname|@colname */ - xpath_expr = psprintf("%s|@%s", colname, colname); - break; - default: - /* Default to @colname for unknown flags */ - xpath_expr = psprintf("@%s", colname); - break; - } - - PG_RETURN_TEXT_P(cstring_to_text(xpath_expr)); -} static void pre_transform_openxml_columns(ParseState *pstate, RangeTableFunc *rtf) @@ -6751,6 +6710,8 @@ pre_transform_openxml_columns(ParseState *pstate, RangeTableFunc *rtf) tsql_docid_node = linitial(rtf->namespaces); tsql_flag = lsecond(rtf->namespaces); + rtf->namespaces = NIL; + /* Set the document expression to retrieve the XML document using the document handle. This creates a function call to tsql_openxml_get_xmldoc * which retrieves the previously prepared XML document based on the document ID from sp_xml_preparedocument. */ From 691ee2cdb7348c50d4331f7df240745511721195 Mon Sep 17 00:00:00 2001 From: Harsh Dubey Date: Fri, 20 Jun 2025 06:33:26 +0000 Subject: [PATCH 12/40] Added the changes of stored procedures Signed-off-by: Harsh Dubey --- contrib/babelfishpg_tsql/src/procedures.c | 36 +++++++---------------- 1 file changed, 10 insertions(+), 26 deletions(-) diff --git a/contrib/babelfishpg_tsql/src/procedures.c b/contrib/babelfishpg_tsql/src/procedures.c index 782a402d167..3e658a3b44f 100644 --- a/contrib/babelfishpg_tsql/src/procedures.c +++ b/contrib/babelfishpg_tsql/src/procedures.c @@ -4454,9 +4454,9 @@ create_xml_handle_columns(void) static char * generate_unique_table_name(const char *base_name) { - char md5[MD5_HASH_LEN + 1]; - const char *errstr = NULL; - bool success; + char md5[MD5_HASH_LEN + 1]; + const char *errstr = NULL; + bool success; /* Generate a unique input string for the MD5 hash */ char *random_input = psprintf("%s%d", base_name, rand()); @@ -4466,9 +4466,10 @@ generate_unique_table_name(const char *base_name) if (unlikely(!success)) ereport(ERROR, - (errcode(ERRCODE_INTERNAL_ERROR), - errmsg("could not compute MD5 hash: %s", errstr))); - + (errcode(ERRCODE_INTERNAL_ERROR), + errmsg("could not compute MD5 hash for XML handle table name generation: %s", errstr ? errstr : "unknown error"), + errdetail("Failed to generate unique table name for base name \"%s\"", base_name))); + /* Create and return table name with prefix and MD5 hash */ return psprintf("%s_%s", base_name, md5); } @@ -4565,9 +4566,6 @@ create_xml_handle_temp_table() * * This function inserts a new XML document and its optional namespace data into * the XML handle temporary table. - * The function temporarily elevates privileges to "bbf_role_admin" to ensure it has - * the necessary permissions to insert data into the table. It also sets the SQL - * dialect to TSQL to ensure proper insertion semantics. * * Returns: * The document_id that can be used to reference this XML document @@ -4584,8 +4582,6 @@ insert_xml_handle_entry(xmltype *xml_data, xmltype *ns_data, int xml_data_length bool is_namespace_null = true; Relation relation; Datum values[7]; - Oid save_userid; - int save_sec_context; int saved_dialect = sql_dialect; HeapTuple tuple; bool nulls[7] = {false, true, false, true, true, false, true}; @@ -4672,14 +4668,10 @@ insert_xml_handle_entry(xmltype *xml_data, xmltype *ns_data, int xml_data_length } tuple = heap_form_tuple(RelationGetDescr(relation), values, nulls); - GetUserIdAndSecContext(&save_userid, &save_sec_context); sql_dialect = SQL_DIALECT_TSQL; PG_TRY(); { - /* Set current user to bbf_role_admin for insert permissions */ - SetUserIdAndSecContext(get_bbf_role_admin_oid(), save_sec_context | SECURITY_LOCAL_USERID_CHANGE); - /* Insert the entries into the table */ simple_heap_insert(relation, tuple); CommandCounterIncrement(); @@ -4695,7 +4687,6 @@ insert_xml_handle_entry(xmltype *xml_data, xmltype *ns_data, int xml_data_length } PG_FINALLY(); { - SetUserIdAndSecContext(save_userid, save_sec_context); sql_dialect = saved_dialect; } PG_END_TRY(); @@ -4715,10 +4706,6 @@ insert_xml_handle_entry(xmltype *xml_data, xmltype *ns_data, int xml_data_length * it from the active_xml_handles bitmap set, making the handle available for * reuse. This is typically called by sp_xml_removedocument to clean up XML * documents when they are no longer needed. - * - * The function temporarily elevates privileges to "bbf_role_admin" to ensure it has - * the necessary permissions to delete data from the table. It also sets the SQL - * dialect to TSQL to ensure proper deletion semantics. */ void delete_xml_handle_entry(int document_id) @@ -4729,8 +4716,6 @@ delete_xml_handle_entry(int document_id) HeapTuple tuple; bool found = false; int curr_handle_counter; - int save_sec_context; - Oid save_userid; int saved_dialect = sql_dialect; MemoryContext oldContext = NULL; bool table_exists = false; @@ -4786,13 +4771,10 @@ delete_xml_handle_entry(int document_id) /* Find and delete the tuple */ if (HeapTupleIsValid(tuple)) { - GetUserIdAndSecContext(&save_userid, &save_sec_context); sql_dialect = SQL_DIALECT_TSQL; PG_TRY(); { - /* Set current user to bbf_role_admin for delete permissions */ - SetUserIdAndSecContext(get_bbf_role_admin_oid(), save_sec_context | SECURITY_LOCAL_USERID_CHANGE); simple_heap_delete(relation, &tuple->t_self); CommandCounterIncrement(); oldContext = MemoryContextSwitchTo(TopMemoryContext); @@ -4801,7 +4783,6 @@ delete_xml_handle_entry(int document_id) } PG_FINALLY(); { - SetUserIdAndSecContext(save_userid, save_sec_context); sql_dialect = saved_dialect; } PG_END_TRY(); @@ -4838,6 +4819,9 @@ reset_cached_xml_handle() /* Reset the table name */ xml_handle_temp_table_name = NULL; + + /* Reset the query environment */ + pltsql_remove_current_query_env(); } Datum From 307e378dea5690a3644ba7ca781baa626df622cc Mon Sep 17 00:00:00 2001 From: Harsh Dubey Date: Fri, 20 Jun 2025 07:40:02 +0000 Subject: [PATCH 13/40] Fixed the indentations Signed-off-by: Harsh Dubey --- .../src/backend_parser/gram-tsql-rule.y | 166 +++++++++--------- contrib/babelfishpg_tsql/src/hooks.c | 109 ++---------- 2 files changed, 97 insertions(+), 178 deletions(-) diff --git a/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-rule.y b/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-rule.y index 620759bf8ee..6f5d2fa7be6 100644 --- a/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-rule.y +++ b/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-rule.y @@ -1801,74 +1801,74 @@ table_ref: relation_expr tsql_table_hint_expr ; openxml_expr: OPENXML '(' a_expr ',' a_expr ')' opt_alias_clause - { - RangeTableFunc *n = makeNode(RangeTableFunc); - n->docexpr = NULL; - n->rowexpr = $5; - n->location = @1; - /* Default flag is 0 when not specified */ - n->namespaces = list_make2((Node*)$3, makeIntConst(0, @1)); - n->columns = NIL; - n->alias = $7; - $$ = (Node *) n; - } + { + RangeTableFunc *n = makeNode(RangeTableFunc); + n->docexpr = NULL; + n->rowexpr = $5; + n->location = @1; + /* Default flag is 0 when not specified */ + n->namespaces = list_make2((Node*)$3, makeIntConst(0, @1)); + n->columns = NIL; + n->alias = $7; + $$ = (Node *) n; + } | OPENXML '(' a_expr ',' a_expr ',' a_expr ')' opt_alias_clause - { - RangeTableFunc *n = makeNode(RangeTableFunc); - n->docexpr = NULL; - n->rowexpr = $5; - n->location = @1; - n->namespaces = list_make2((Node *)$3, (Node *)$7); - n->columns = NIL; - n->alias = $9; - $$ = (Node *) n; - } + { + RangeTableFunc *n = makeNode(RangeTableFunc); + n->docexpr = NULL; + n->rowexpr = $5; + n->location = @1; + n->namespaces = list_make2((Node *)$3, (Node *)$7); + n->columns = NIL; + n->alias = $9; + $$ = (Node *) n; + } | OPENXML '(' a_expr ',' a_expr ')' WITH_table TABLE qualified_name opt_alias_clause - { - RangeTableFunc *n = makeNode(RangeTableFunc); - n->docexpr = NULL; - n->rowexpr = $5; - n->location = @1; - /* Default flag is 0 when not specified */ - n->namespaces = list_make2((Node *)$3, makeIntConst(0, @1)); - n->columns = list_make1($9); - n->alias = $10; - $$ = (Node *) n; - } + { + RangeTableFunc *n = makeNode(RangeTableFunc); + n->docexpr = NULL; + n->rowexpr = $5; + n->location = @1; + /* Default flag is 0 when not specified */ + n->namespaces = list_make2((Node *)$3, makeIntConst(0, @1)); + n->columns = list_make1($9); + n->alias = $10; + $$ = (Node *) n; + } | OPENXML '(' a_expr ',' a_expr ',' a_expr ')' WITH_table TABLE qualified_name opt_alias_clause - { - RangeTableFunc *n = makeNode(RangeTableFunc); - n->docexpr = NULL; - n->rowexpr = $5; - n->location = @1; - n->namespaces = list_make2((Node *)$3, (Node *)$7); - n->columns = list_make1($11); - n->alias = $12; - $$ = (Node *) n; - } - | OPENXML '(' a_expr ',' a_expr ')' WITH_paren '(' openxml_column_list ')' opt_alias_clause - { - RangeTableFunc *n = makeNode(RangeTableFunc); - n->docexpr = NULL; - n->rowexpr = $5; - n->location = @1; - /* Default flag is 0 when not specified */ - n->columns = $9; - n->namespaces = list_make2((Node *)$3, makeIntConst(0, @1)); - n->alias = $11; - $$ = (Node *) n; - } - | OPENXML '(' a_expr ',' a_expr ',' a_expr ')' WITH_paren '(' openxml_column_list ')' opt_alias_clause - { - RangeTableFunc *n = makeNode(RangeTableFunc); - n->docexpr = NULL; - n->rowexpr = $5; - n->columns = $11; - n->location = @1; - n->namespaces = list_make2((Node *)$3, (Node *)$7); - n->alias = $13; - $$ = (Node *) n; - } + { + RangeTableFunc *n = makeNode(RangeTableFunc); + n->docexpr = NULL; + n->rowexpr = $5; + n->location = @1; + n->namespaces = list_make2((Node *)$3, (Node *)$7); + n->columns = list_make1($11); + n->alias = $12; + $$ = (Node *) n; + } + | OPENXML '(' a_expr ',' a_expr ')' WITH_paren '(' openxml_column_list ')' opt_alias_clause + { + RangeTableFunc *n = makeNode(RangeTableFunc); + n->docexpr = NULL; + n->rowexpr = $5; + n->location = @1; + /* Default flag is 0 when not specified */ + n->columns = $9; + n->namespaces = list_make2((Node *)$3, makeIntConst(0, @1)); + n->alias = $11; + $$ = (Node *) n; + } + | OPENXML '(' a_expr ',' a_expr ',' a_expr ')' WITH_paren '(' openxml_column_list ')' opt_alias_clause + { + RangeTableFunc *n = makeNode(RangeTableFunc); + n->docexpr = NULL; + n->rowexpr = $5; + n->columns = $11; + n->location = @1; + n->namespaces = list_make2((Node *)$3, (Node *)$7); + n->alias = $13; + $$ = (Node *) n; + } ; openxml_column_list: openxml_column_el { $$ = list_make1($1); } @@ -1877,29 +1877,29 @@ openxml_column_list: openxml_column_el { $$ = list_make1($1); openxml_column_el: ColId Typename - { - RangeTableFuncCol *fc = makeNode(RangeTableFuncCol); + { + RangeTableFuncCol *fc = makeNode(RangeTableFuncCol); - fc->colname = $1; - fc->typeName = $2; - fc->colexpr = NULL; - fc->coldefexpr = NULL; - fc->location = @1; + fc->colname = $1; + fc->typeName = $2; + fc->colexpr = NULL; + fc->coldefexpr = NULL; + fc->location = @1; - $$ = (Node *) fc; - } + $$ = (Node *) fc; + } | ColId Typename Sconst - { - RangeTableFuncCol *fc = makeNode(RangeTableFuncCol); + { + RangeTableFuncCol *fc = makeNode(RangeTableFuncCol); - fc->colname = $1; - fc->typeName = $2; - fc->colexpr = (Node *) makeStringConst($3, @1); - fc->coldefexpr = NULL; - fc->location = @1; + fc->colname = $1; + fc->typeName = $2; + fc->colexpr = (Node *) makeStringConst($3, @1); + fc->coldefexpr = NULL; + fc->location = @1; - $$ = (Node *) fc; - } + $$ = (Node *) fc; + } ; openjson_expr: OPENJSON '(' a_expr ')' opt_alias_clause diff --git a/contrib/babelfishpg_tsql/src/hooks.c b/contrib/babelfishpg_tsql/src/hooks.c index 0e35a9de21e..43e2fae4b2d 100644 --- a/contrib/babelfishpg_tsql/src/hooks.c +++ b/contrib/babelfishpg_tsql/src/hooks.c @@ -6578,8 +6578,8 @@ fetch_table_schema(RangeVar *relation, Node *flag) RangeTableFuncCol *fc; char *colname; - /* Skip dropped and generated columns */ - if (att->attisdropped || att->attgenerated) + /* Skip dropped columns */ + if (att->attisdropped) continue; colname = NameStr(att->attname); @@ -6606,97 +6606,14 @@ fetch_table_schema(RangeVar *relation, Node *flag) } /* - * transformOpenxml_expr - Process OPENXML expressions for T-SQL compatibility + * pre_transform_openxml_columns - Transform OPENXML syntax to XMLTABLE-compatible format * - * This function handles the transformation of OPENXML expressions by either: - * 1. Using a referenced table's schema to generate appropriate column definitions, or - * 2. Processing explicitly provided columns by generating XPath expressions based on - * column names and the specified flag parameter. - * - * The function ensures each column has a proper col expression using the tsql_openxml_get_colpattern function. - */ -// static void -// transformOpenxml_expr(ParseState *pstate, Openxml_expr *expr) -// { - -// /* If a table reference is provided, get the columns from that table */ -// if (expr->table_ref != NULL) -// { -// expr->columns = fetch_table_schema(expr->table_ref, expr->tsql_flag); -// } -// else if (expr->columns != NIL) -// { -// /* Handle case where columns are provided but no table name */ -// ListCell *lc; -// foreach(lc, expr->columns) -// { -// RangeTableFuncCol *fc = (RangeTableFuncCol *) lfirst(lc); - -// /* If no column expression is provided, generate one based on the flag */ -// if (fc->colexpr == NULL) -// { -// /* To get original column name, utilize location of ColumnDef and query string. For colexpr, we need orignal name of columns (no downcase or uppercase) */ -// const char *column_name_start = pstate->p_sourcetext + fc->location; -// char *original_name = extract_identifier(column_name_start, NULL); - -// /* Create an XPath expression for the column using tsql_openxml_get_colpattern. This builds a function call to generate the appropriate XPath pattern -// * based on the column name and the OPENXML flag parameter -// */ -// fc->colexpr = (Node *) makeFuncCall(list_make2(makeString("sys"), makeString("tsql_openxml_get_colpattern")), list_make2(makeStringConst(original_name, -1), expr->tsql_flag), COERCE_EXPLICIT_CALL, -1); -// } -// } -// } - -// } - -/* - * bbf_transformFromClauseItem - Transform T-SQL OPENXML expressions in FROM clauses - * - * This hook function handles the transformation of T-SQL specific OPENXML expressions - * in FROM clauses into PostgreSQL's RangeTableFunc structures. It converts the - * OPENXML syntax into appropriate function calls to extract and process XML data. - * The function only processes nodes when in T-SQL dialect mode. + * This hook function converts TSQL OPENXML syntax into PostgreSQL XMLTABLE format + * by transforming the RangeTableFunc structure. It extracts the document handle + * and flag from the namespaces list, creates a document expression using + * tsql_openxml_get_xmldoc, and generates appropriate XPath column expressions + * using tsql_openxml_get_colpattern for TSQL compatibility. */ -// static Node * -// bbf_transformFromClauseItem(ParseState *pstate, Node *n, ParseNamespaceItem **top_nsitem, List **namespace) -// { -// if (sql_dialect != SQL_DIALECT_TSQL) -// return NULL; - -// if (IsA(n, Openxml_expr)) -// { -// /* table function is like a plain relation */ -// RangeTblRef *rtr; -// ParseNamespaceItem *nsitem; -// RangeTableFunc *rtf = makeNode(RangeTableFunc); -// Openxml_expr *expr = (Openxml_expr *) n; - -// transformOpenxml_expr(pstate, expr); - -// /* Set the document expression to retrieve the XML document using the document handle. This creates a function call to tsql_openxml_get_xmldoc -// * which retrieves the previously prepared XML document based on the document ID from sp_xml_preparedocument. -// */ -// rtf->docexpr = (Node *) makeFuncCall(list_make2(makeString("sys"), makeString("tsql_openxml_get_xmldoc")), list_make1(expr->tsql_docid), COERCE_EXPLICIT_CALL, -1); - -// rtf->rowexpr = expr->rowexpr; -// rtf->columns = expr->columns; -// rtf->alias = expr->alias; -// rtf->location = expr->location; -// rtf->namespaces = NIL; - -// nsitem = bbf_transformRangeTableFunc(pstate, rtf); - -// *top_nsitem = nsitem; -// *namespace = list_make1(nsitem); -// rtr = makeNode(RangeTblRef); -// rtr->rtindex = nsitem->p_rtindex; -// return (Node *) rtr; -// } - -// return NULL; -// } - - static void pre_transform_openxml_columns(ParseState *pstate, RangeTableFunc *rtf) { @@ -6712,7 +6629,8 @@ pre_transform_openxml_columns(ParseState *pstate, RangeTableFunc *rtf) rtf->namespaces = NIL; - /* Set the document expression to retrieve the XML document using the document handle. This creates a function call to tsql_openxml_get_xmldoc + /* + * Set the document expression to retrieve the XML document using the document handle. This creates a function call to tsql_openxml_get_xmldoc * which retrieves the previously prepared XML document based on the document ID from sp_xml_preparedocument. */ rtf->docexpr = (Node *) makeFuncCall(list_make2(makeString("sys"), makeString("tsql_openxml_get_xmldoc")), list_make1(tsql_docid_node), COERCE_EXPLICIT_CALL, -1); @@ -6744,9 +6662,10 @@ pre_transform_openxml_columns(ParseState *pstate, RangeTableFunc *rtf) if (original_name == NULL) original_name = fc->colname; - /* Create an XPath expression for the column using tsql_openxml_get_colpattern. This builds a function call to generate the appropriate XPath pattern - * based on the column name and the OPENXML flag parameter - */ + /* + * Create an XPath expression for the column using tsql_openxml_get_colpattern. This builds a function call to generate the appropriate XPath pattern + * based on the column name and the OPENXML flag parameter + */ fc->colexpr = (Node *) makeFuncCall(list_make2(makeString("sys"), makeString("tsql_openxml_get_colpattern")), list_make2(makeStringConst(original_name, -1), tsql_flag), COERCE_EXPLICIT_CALL, -1); } } From 0b3ae28fec6a40e20402e248e5d81218854cbe71 Mon Sep 17 00:00:00 2001 From: Harsh Dubey Date: Fri, 20 Jun 2025 16:02:15 +0000 Subject: [PATCH 14/40] Retrigger workflows From 56e46169a9fe5719dc4ed20af20bcc1bdd62279e Mon Sep 17 00:00:00 2001 From: Harsh Dubey Date: Sun, 22 Jun 2025 19:48:06 +0000 Subject: [PATCH 15/40] Added the cases of flag value more than 3 Signed-off-by: Harsh Dubey --- contrib/babelfishpg_tsql/src/procedures.c | 11 ++ .../openxml_with_clause-vu-verify.out | 135 ++++++++++++++++++ .../xml/openxml_with_clause-vu-verify.sql | 115 +++++++++++++++ 3 files changed, 261 insertions(+) diff --git a/contrib/babelfishpg_tsql/src/procedures.c b/contrib/babelfishpg_tsql/src/procedures.c index 3e658a3b44f..fe2ffb06310 100644 --- a/contrib/babelfishpg_tsql/src/procedures.c +++ b/contrib/babelfishpg_tsql/src/procedures.c @@ -5012,6 +5012,17 @@ tsql_openxml_get_colpattern(PG_FUNCTION_ARGS) char *xpath_expr; int flag = PG_GETARG_INT32(1); char *colname = text_to_cstring(PG_GETARG_TEXT_PP(0)); + + /* Check for negative flag values */ + if (flag < 0) + { + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("Invalid flag value %d for OPENXML", flag))); + } + + /* Normalize the flag value to 0-3 */ + flag = flag % 4; switch (flag) { diff --git a/test/JDBC/expected/openxml_with_clause-vu-verify.out b/test/JDBC/expected/openxml_with_clause-vu-verify.out index 2b3a8cda3bd..b9f813d0167 100644 --- a/test/JDBC/expected/openxml_with_clause-vu-verify.out +++ b/test/JDBC/expected/openxml_with_clause-vu-verify.out @@ -280,3 +280,138 @@ O4 #!#1996-01-20 00:00:00.0#!#10000.0 DROP TABLE test_openxml_table; GO + + + +-- If flag value more than 3 +DECLARE @XmlDocumentHandle int; +DECLARE @XmlDocument nvarchar(1000); +SET @XmlDocument = N' + + VINET + Paul Henriot + + + + + + + + + + +'; +EXEC sp_xml_preparedocument @XmlDocumentHandle OUTPUT, @XmlDocument; +SELECT * +FROM OPENXML (@XmlDocumentHandle, '/ROOT/Customer', 4) + WITH (CustomerID varchar(10), + ContactName varchar(20)); +EXEC sp_xml_removedocument @XmlDocumentHandle; +GO +~~START~~ +varchar#!#varchar +#!# +LILAS#!#Carlos Gonzalez +~~END~~ + + + + +DECLARE @XmlDocumentHandle int; +DECLARE @XmlDocument nvarchar(1000); +SET @XmlDocument = N' + + VINET + Paul Henriot + + + + + + + + + + +'; +EXEC sp_xml_preparedocument @XmlDocumentHandle OUTPUT, @XmlDocument; +SELECT * +FROM OPENXML (@XmlDocumentHandle, '/ROOT/Customer', 7) + WITH (CustomerID varchar(10), + ContactName varchar(20)); +EXEC sp_xml_removedocument @XmlDocumentHandle; +GO +~~START~~ +varchar#!#varchar +VINET#!#Paul Henriot +LILAS#!#Carlos Gonzalez +~~END~~ + + + + +-- negative flag value gives error +DECLARE @XmlDocumentHandle int; +DECLARE @XmlDocument nvarchar(1000); +SET @XmlDocument = N' + + VINET + Paul Henriot + + + + + + + + + + +'; +EXEC sp_xml_preparedocument @XmlDocumentHandle OUTPUT, @XmlDocument; +SELECT * +FROM OPENXML (@XmlDocumentHandle, '/ROOT/Customer', -1) + WITH (CustomerID varchar(10), + ContactName varchar(20)); +EXEC sp_xml_removedocument @XmlDocumentHandle; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Invalid flag value -1 for OPENXML)~~ + + + + +-- colpattern is case sensitive (this gives null) +DECLARE @XmlDocumentHandle int; +DECLARE @XmlDocument nvarchar(1000); +SET @XmlDocument = N' + + VINET + Paul Henriot + + + + + + + + + + +'; +EXEC sp_xml_preparedocument @XmlDocumentHandle OUTPUT, @XmlDocument; +SELECT * +FROM OPENXML (@XmlDocumentHandle, '/root/customer', 4) + WITH (CustomerID varchar(10), + ContactName varchar(20)); +EXEC sp_xml_removedocument @XmlDocumentHandle; +GO +~~START~~ +varchar#!#varchar +~~END~~ + diff --git a/test/JDBC/input/xml/openxml_with_clause-vu-verify.sql b/test/JDBC/input/xml/openxml_with_clause-vu-verify.sql index ea818249754..2627e1fa007 100644 --- a/test/JDBC/input/xml/openxml_with_clause-vu-verify.sql +++ b/test/JDBC/input/xml/openxml_with_clause-vu-verify.sql @@ -229,3 +229,118 @@ EXEC sp_xml_removedocument @docHandle; GO DROP TABLE test_openxml_table; GO + +-- If flag value more than 3 +DECLARE @XmlDocumentHandle int; +DECLARE @XmlDocument nvarchar(1000); +SET @XmlDocument = N' + + VINET + Paul Henriot + + + + + + + + + + +'; + +EXEC sp_xml_preparedocument @XmlDocumentHandle OUTPUT, @XmlDocument; + +SELECT * +FROM OPENXML (@XmlDocumentHandle, '/ROOT/Customer', 4) + WITH (CustomerID varchar(10), + ContactName varchar(20)); +EXEC sp_xml_removedocument @XmlDocumentHandle; +GO + +DECLARE @XmlDocumentHandle int; +DECLARE @XmlDocument nvarchar(1000); +SET @XmlDocument = N' + + VINET + Paul Henriot + + + + + + + + + + +'; + +EXEC sp_xml_preparedocument @XmlDocumentHandle OUTPUT, @XmlDocument; + +SELECT * +FROM OPENXML (@XmlDocumentHandle, '/ROOT/Customer', 7) + WITH (CustomerID varchar(10), + ContactName varchar(20)); +EXEC sp_xml_removedocument @XmlDocumentHandle; +GO + +-- negative flag value gives error +DECLARE @XmlDocumentHandle int; +DECLARE @XmlDocument nvarchar(1000); +SET @XmlDocument = N' + + VINET + Paul Henriot + + + + + + + + + + +'; + +EXEC sp_xml_preparedocument @XmlDocumentHandle OUTPUT, @XmlDocument; + +SELECT * +FROM OPENXML (@XmlDocumentHandle, '/ROOT/Customer', -1) + WITH (CustomerID varchar(10), + ContactName varchar(20)); +EXEC sp_xml_removedocument @XmlDocumentHandle; +GO + +-- colpattern is case sensitive (this gives null) +DECLARE @XmlDocumentHandle int; +DECLARE @XmlDocument nvarchar(1000); +SET @XmlDocument = N' + + VINET + Paul Henriot + + + + + + + + + + +'; + +EXEC sp_xml_preparedocument @XmlDocumentHandle OUTPUT, @XmlDocument; + +SELECT * +FROM OPENXML (@XmlDocumentHandle, '/root/customer', 4) + WITH (CustomerID varchar(10), + ContactName varchar(20)); +EXEC sp_xml_removedocument @XmlDocumentHandle; +GO \ No newline at end of file From 4d6105642d242535a868268a8298edbe8482fdfb Mon Sep 17 00:00:00 2001 From: Harsh Dubey Date: Mon, 23 Jun 2025 06:16:06 +0000 Subject: [PATCH 16/40] Retrigger workflows Signed-off-by: Harsh Dubey --- .../openxml_with_clause-vu-verify.out | 33 ------------------- .../xml/openxml_with_clause-vu-verify.sql | 29 ---------------- 2 files changed, 62 deletions(-) diff --git a/test/JDBC/expected/openxml_with_clause-vu-verify.out b/test/JDBC/expected/openxml_with_clause-vu-verify.out index b9f813d0167..6b8b3b697f6 100644 --- a/test/JDBC/expected/openxml_with_clause-vu-verify.out +++ b/test/JDBC/expected/openxml_with_clause-vu-verify.out @@ -352,39 +352,6 @@ LILAS#!#Carlos Gonzalez --- negative flag value gives error -DECLARE @XmlDocumentHandle int; -DECLARE @XmlDocument nvarchar(1000); -SET @XmlDocument = N' - - VINET - Paul Henriot - - - - - - - - - - -'; -EXEC sp_xml_preparedocument @XmlDocumentHandle OUTPUT, @XmlDocument; -SELECT * -FROM OPENXML (@XmlDocumentHandle, '/ROOT/Customer', -1) - WITH (CustomerID varchar(10), - ContactName varchar(20)); -EXEC sp_xml_removedocument @XmlDocumentHandle; -GO -~~ERROR (Code: 33557097)~~ - -~~ERROR (Message: Invalid flag value -1 for OPENXML)~~ - - - - -- colpattern is case sensitive (this gives null) DECLARE @XmlDocumentHandle int; DECLARE @XmlDocument nvarchar(1000); diff --git a/test/JDBC/input/xml/openxml_with_clause-vu-verify.sql b/test/JDBC/input/xml/openxml_with_clause-vu-verify.sql index 2627e1fa007..4ccaac63256 100644 --- a/test/JDBC/input/xml/openxml_with_clause-vu-verify.sql +++ b/test/JDBC/input/xml/openxml_with_clause-vu-verify.sql @@ -287,35 +287,6 @@ FROM OPENXML (@XmlDocumentHandle, '/ROOT/Customer', 7) EXEC sp_xml_removedocument @XmlDocumentHandle; GO --- negative flag value gives error -DECLARE @XmlDocumentHandle int; -DECLARE @XmlDocument nvarchar(1000); -SET @XmlDocument = N' - - VINET - Paul Henriot - - - - - - - - - - -'; - -EXEC sp_xml_preparedocument @XmlDocumentHandle OUTPUT, @XmlDocument; - -SELECT * -FROM OPENXML (@XmlDocumentHandle, '/ROOT/Customer', -1) - WITH (CustomerID varchar(10), - ContactName varchar(20)); -EXEC sp_xml_removedocument @XmlDocumentHandle; -GO - -- colpattern is case sensitive (this gives null) DECLARE @XmlDocumentHandle int; DECLARE @XmlDocument nvarchar(1000); From 40144decba4e61742affcc01dcfb85a704fd4021 Mon Sep 17 00:00:00 2001 From: Harsh Dubey Date: Tue, 24 Jun 2025 10:37:10 +0000 Subject: [PATCH 17/40] Added some more testcases of openxml with clause Signed-off-by: Harsh Dubey --- .../babelfishpg_tsql/sql/sys_functions.sql | 4 +- .../src/backend_parser/gram-tsql-rule.y | 25 +- contrib/babelfishpg_tsql/src/hooks.c | 7 +- contrib/babelfishpg_tsql/src/procedures.c | 21 +- .../src/tsqlUnsupportedFeatureHandler.cpp | 2 +- .../openxml_with_clause-vu-cleanup.out | 17 + .../openxml_with_clause-vu-prepare.out | 37 ++ .../openxml_with_clause-vu-verify.out | 366 +++++++++++++++++- .../xml/openxml_with_clause-vu-cleanup.sql | 17 + .../xml/openxml_with_clause-vu-prepare.sql | 37 ++ .../xml/openxml_with_clause-vu-verify.sql | 288 +++++++++++++- 11 files changed, 777 insertions(+), 44 deletions(-) create mode 100644 test/JDBC/expected/openxml_with_clause-vu-cleanup.out create mode 100644 test/JDBC/expected/openxml_with_clause-vu-prepare.out create mode 100644 test/JDBC/input/xml/openxml_with_clause-vu-cleanup.sql create mode 100644 test/JDBC/input/xml/openxml_with_clause-vu-prepare.sql diff --git a/contrib/babelfishpg_tsql/sql/sys_functions.sql b/contrib/babelfishpg_tsql/sql/sys_functions.sql index 0514a35bb97..7800d363e1f 100644 --- a/contrib/babelfishpg_tsql/sql/sys_functions.sql +++ b/contrib/babelfishpg_tsql/sql/sys_functions.sql @@ -4032,12 +4032,12 @@ AS 'babelfishpg_tsql', 'tsql_openjson_with' LANGUAGE C STRICT IMMUTABLE PARALLEL CREATE OR REPLACE FUNCTION sys.tsql_openxml_get_xmldoc(int) RETURNS xml AS 'babelfishpg_tsql', 'tsql_openxml_get_xmldoc' -LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE; +LANGUAGE C STRICT; CREATE OR REPLACE FUNCTION sys.tsql_openxml_get_colpattern(text,int) RETURNS sys.nvarchar AS 'babelfishpg_tsql', 'tsql_openxml_get_colpattern' -LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE; +LANGUAGE C STRICT; CREATE OR REPLACE FUNCTION sys.sp_datatype_info_helper( IN odbcVer smallint, diff --git a/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-rule.y b/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-rule.y index 6f5d2fa7be6..cb686c04d84 100644 --- a/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-rule.y +++ b/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-rule.y @@ -1800,30 +1800,7 @@ table_ref: relation_expr tsql_table_hint_expr } ; -openxml_expr: OPENXML '(' a_expr ',' a_expr ')' opt_alias_clause - { - RangeTableFunc *n = makeNode(RangeTableFunc); - n->docexpr = NULL; - n->rowexpr = $5; - n->location = @1; - /* Default flag is 0 when not specified */ - n->namespaces = list_make2((Node*)$3, makeIntConst(0, @1)); - n->columns = NIL; - n->alias = $7; - $$ = (Node *) n; - } - | OPENXML '(' a_expr ',' a_expr ',' a_expr ')' opt_alias_clause - { - RangeTableFunc *n = makeNode(RangeTableFunc); - n->docexpr = NULL; - n->rowexpr = $5; - n->location = @1; - n->namespaces = list_make2((Node *)$3, (Node *)$7); - n->columns = NIL; - n->alias = $9; - $$ = (Node *) n; - } - | OPENXML '(' a_expr ',' a_expr ')' WITH_table TABLE qualified_name opt_alias_clause +openxml_expr: OPENXML '(' a_expr ',' a_expr ')' WITH_table TABLE qualified_name opt_alias_clause { RangeTableFunc *n = makeNode(RangeTableFunc); n->docexpr = NULL; diff --git a/contrib/babelfishpg_tsql/src/hooks.c b/contrib/babelfishpg_tsql/src/hooks.c index 43e2fae4b2d..9b0febf7bb7 100644 --- a/contrib/babelfishpg_tsql/src/hooks.c +++ b/contrib/babelfishpg_tsql/src/hooks.c @@ -6577,7 +6577,7 @@ fetch_table_schema(RangeVar *relation, Node *flag) Form_pg_attribute att = TupleDescAttr(tupdesc, i); RangeTableFuncCol *fc; char *colname; - + /* Skip dropped columns */ if (att->attisdropped) continue; @@ -6638,8 +6638,9 @@ pre_transform_openxml_columns(ParseState *pstate, RangeTableFunc *rtf) if (rtf->columns != NIL) { Node *first_col = linitial(rtf->columns); - - if (IsA(first_col, RangeVar)) + + /* Check if we have exactly one column and it's a table reference */ + if (list_length(rtf->columns) == 1 && IsA(first_col, RangeVar)) { table_ref = (RangeVar *) first_col; /* Fetch the table schema and generate column definitions with appropriate XPath expressions */ diff --git a/contrib/babelfishpg_tsql/src/procedures.c b/contrib/babelfishpg_tsql/src/procedures.c index fe2ffb06310..4421273ea24 100644 --- a/contrib/babelfishpg_tsql/src/procedures.c +++ b/contrib/babelfishpg_tsql/src/procedures.c @@ -4929,6 +4929,7 @@ sp_xml_removedocument(PG_FUNCTION_ARGS) /* * Function to retrieve XML document from temporary table using document ID */ +#define XML_HANDLE_DOC_COLUMN_NUM 6 Datum tsql_openxml_get_xmldoc(PG_FUNCTION_ARGS) { @@ -4941,6 +4942,7 @@ tsql_openxml_get_xmldoc(PG_FUNCTION_ARGS) Datum result = (Datum) 0; bool isnull = true; EphemeralNamedRelation enr = NULL; + bool table_exists = false; /* Check if the temporary table exists */ if (xml_handle_temp_table_name != NULL) @@ -4949,14 +4951,15 @@ tsql_openxml_get_xmldoc(PG_FUNCTION_ARGS) if (enr) { relation = relation_open(enr->md.reliddesc, RowExclusiveLock); + table_exists = true; } } - if (!OidIsValid(enr->md.reliddesc)) + if (!table_exists) { ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("XML document with ID %d not found", document_id))); + errmsg("Could not find prepared statement with handle %d", document_id))); } ScanKeyInit(&skey[0], @@ -4970,7 +4973,7 @@ tsql_openxml_get_xmldoc(PG_FUNCTION_ARGS) if (HeapTupleIsValid(tuple)) { /* Get the XML document from column 6 (doc) */ - result = heap_getattr(tuple, 6, RelationGetDescr(relation), &isnull); + result = heap_getattr(tuple, XML_HANDLE_DOC_COLUMN_NUM, RelationGetDescr(relation), &isnull); if (!isnull) { @@ -4987,10 +4990,10 @@ tsql_openxml_get_xmldoc(PG_FUNCTION_ARGS) if (found) PG_RETURN_DATUM(result); - /* If we get here , we did not find the document */ + /* If we didn't find the handle , throw an error */ ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("XML document with ID %d not found", document_id))); + errmsg("Could not find prepared statement with handle %d", document_id))); PG_RETURN_NULL(); } @@ -5013,6 +5016,14 @@ tsql_openxml_get_colpattern(PG_FUNCTION_ARGS) int flag = PG_GETARG_INT32(1); char *colname = text_to_cstring(PG_GETARG_TEXT_PP(0)); + /* Check if colname is NULL or empty */ + if (colname == NULL || strlen(colname) == 0) + { + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("Column name cannot be NULL or empty for OPENXML"))); + } + /* Check for negative flag values */ if (flag < 0) { diff --git a/contrib/babelfishpg_tsql/src/tsqlUnsupportedFeatureHandler.cpp b/contrib/babelfishpg_tsql/src/tsqlUnsupportedFeatureHandler.cpp index 90add5262ee..ed220ffbb88 100644 --- a/contrib/babelfishpg_tsql/src/tsqlUnsupportedFeatureHandler.cpp +++ b/contrib/babelfishpg_tsql/src/tsqlUnsupportedFeatureHandler.cpp @@ -182,7 +182,7 @@ class TsqlUnsupportedFeatureHandlerImpl : public TsqlUnsupportedFeatureHandler antlrcpp::Any visitFunction_call(TSqlParser::Function_callContext *ctx) override; antlrcpp::Any visitAggregate_windowed_function(TSqlParser::Aggregate_windowed_functionContext *ctx) override; antlrcpp::Any visitRowset_function(TSqlParser::Rowset_functionContext *ctx) override { - if (!ctx->open_json() && (!pltsql_enable_linked_servers || !ctx->open_query()) && !ctx->open_xml()) { + if (!ctx->open_json() && (!pltsql_enable_linked_servers || !ctx->open_query()) && !ctx->open_xml()->WITH()) { handle(INSTR_UNSUPPORTED_TSQL_ROWSET_FUNCTION, "rowset function", getLineAndPos(ctx)); } return visitChildren(ctx); diff --git a/test/JDBC/expected/openxml_with_clause-vu-cleanup.out b/test/JDBC/expected/openxml_with_clause-vu-cleanup.out new file mode 100644 index 00000000000..7cdda0c3e79 --- /dev/null +++ b/test/JDBC/expected/openxml_with_clause-vu-cleanup.out @@ -0,0 +1,17 @@ +DROP TABLE test_openxml_table; +GO + +DROP TABLE test_openxml_table_2; +GO + +DROP TABLE very_long_table_name_that_exceeds_sixty_four_characters_limit_test; +GO + +DROP TABLE test_long_columns; +GO + +DROP TABLE mixed_length_names; +GO + +DROP TABLE employee_defaults; +GO diff --git a/test/JDBC/expected/openxml_with_clause-vu-prepare.out b/test/JDBC/expected/openxml_with_clause-vu-prepare.out new file mode 100644 index 00000000000..343c997fe56 --- /dev/null +++ b/test/JDBC/expected/openxml_with_clause-vu-prepare.out @@ -0,0 +1,37 @@ +CREATE TABLE test_openxml_table(oid char(5), date datetime, amount float); +GO + +CREATE TABLE test_openxml_table_2(oid char(5), Date datetime, amount float); +GO + +CREATE TABLE very_long_table_name_that_exceeds_sixty_four_characters_limit_test ( + id INT, + name VARCHAR(50), + value INT +); +GO + +CREATE TABLE test_long_columns ( + very_long_column_name_that_definitely_exceeds_sixty_four_characters_limit_test INT, + another_extremely_long_column_name_exceeding_standard_limits_for_testing VARCHAR(50), + short_col INT +); +GO + +CREATE TABLE mixed_length_names ( + id INT, + extremely_long_column_name_that_exceeds_the_standard_sixty_four_character_limit_for_identifiers VARCHAR(200), + short VARCHAR(50) +); +GO + +CREATE TABLE employee_defaults ( + id INT IDENTITY(1,1) PRIMARY KEY, + name VARCHAR(50) NOT NULL, + department VARCHAR(20) DEFAULT 'Unknown', + salary DECIMAL(10,2) DEFAULT 0.00, + hire_date DATETIME DEFAULT GETDATE(), + status VARCHAR(10) DEFAULT 'Active', + CHECK (salary >= 0) +); +GO diff --git a/test/JDBC/expected/openxml_with_clause-vu-verify.out b/test/JDBC/expected/openxml_with_clause-vu-verify.out index 6b8b3b697f6..538d20b4c30 100644 --- a/test/JDBC/expected/openxml_with_clause-vu-verify.out +++ b/test/JDBC/expected/openxml_with_clause-vu-verify.out @@ -247,7 +247,6 @@ LILAS#!#Carlos Gonzalez -- If tablename is given -CREATE TABLE test_openxml_table(oid char(5), date datetime, amount float); DECLARE @docHandle int; DECLARE @XmlDocument varchar(1000); SET @xmlDocument = N' @@ -278,8 +277,6 @@ O3 #!#1999-07-14 00:00:00.0#!#100.0 O4 #!#1996-01-20 00:00:00.0#!#10000.0 ~~END~~ -DROP TABLE test_openxml_table; -GO @@ -352,7 +349,7 @@ LILAS#!#Carlos Gonzalez --- colpattern is case sensitive (this gives null) +-- rowpattern is case sensitive (this gives null) DECLARE @XmlDocumentHandle int; DECLARE @XmlDocument nvarchar(1000); SET @XmlDocument = N' @@ -382,3 +379,364 @@ GO varchar#!#varchar ~~END~~ + + + +-- colpattern is case sensitive +DECLARE @DocHandle int; +DECLARE @XmlDocument nvarchar(1000); +SET @XmlDocument = N' + + + + + + + + + + + +'; +EXEC sp_xml_preparedocument @DocHandle OUTPUT, @XmlDocument; +SELECT * +FROM OPENXML (@DocHandle, '/ROOT/Customer',1) + WITH (customerid varchar(10) , + contactname varchar(20)); +EXEC sp_xml_removedocument @DocHandle; +GO +~~START~~ +varchar#!#varchar +#!# +#!# +~~END~~ + + + + +-- negative flag value +DECLARE @XmlDocumentHandle int; +DECLARE @XmlDocument nvarchar(1000); +SET @XmlDocument = N' + + VINET + Paul Henriot + + + + + + + + + + +'; +EXEC sp_xml_preparedocument @XmlDocumentHandle OUTPUT, @XmlDocument; +SELECT * +FROM OPENXML (@XmlDocumentHandle, '/ROOT/Customer', -1) + WITH (CustomerID varchar(10), + ContactName varchar(20)); +EXEC sp_xml_removedocument @XmlDocumentHandle; +GO +~~START~~ +varchar#!#varchar +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Invalid flag value -1 for OPENXML)~~ + + + + +-- Mixed attributes +DECLARE @DocHandle int; +DECLARE @XmlDocument nvarchar(1000); +SET @XmlDocument = N' + + The Great Novel + + John + Author + 4.5 + + + Book House + 2023 + 29.99 + + +'; +EXEC sp_xml_preparedocument @DocHandle OUTPUT, @XmlDocument; +SELECT * +FROM OPENXML (@DocHandle, '/Library/Book', 2) +WITH ( + ISBN varchar(20), + Category varchar(50), + Title varchar(100) 'Title', + AuthorFirstName varchar(50) 'Author/FirstName', + AuthorLastName varchar(50) 'Author/LastName', + Rating decimal(3,1) 'Author/Rating', + Publisher varchar(50) 'Publication/Publisher', + PublishYear int 'Publication/Year', + Price decimal(10,2) 'Publication/Price', + Currency varchar(3) 'Publication/Price/@currency' +); +EXEC sp_xml_removedocument @DocHandle; +GO +~~START~~ +varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#numeric#!#varchar#!#int#!#numeric#!#varchar +#!##!#The Great Novel#!#John#!#Author#!#4.5#!#Book House#!#2023#!#29.99#!#USD +~~END~~ + + + + + + +-- Nested elements +DECLARE @DocHandle int; +DECLARE @XmlDocument nvarchar(2000); +SET @XmlDocument = N' + + + Acme Corp +
123 Business St
+
+ + + Laptop + 2 + 999.99 + 0.10 + + + Mouse + 5 + 24.99 + 0.05 + + +
+
'; +EXEC sp_xml_preparedocument @DocHandle OUTPUT, @XmlDocument; +SELECT * +FROM OPENXML (@DocHandle, '/Invoices/Invoice', 2) +WITH ( + InvoiceID varchar(10), + InvoiceDate date '@Date', + CustomerID varchar(10) 'Customer/@ID', + CustomerName varchar(50) 'Customer/Name', + CustomerAddress varchar(100) 'Customer/Address' +); +SELECT * +FROM OPENXML (@DocHandle, '/Invoices/Invoice/Items/Item', 2) +WITH ( + InvoiceID varchar(10) '../../../@InvoiceID', + SKU varchar(10) '@SKU', + Description varchar(100) 'Description', + Quantity int 'Quantity', + UnitPrice decimal(10,2) 'UnitPrice', + Discount decimal(4,2) 'Discount' +); +EXEC sp_xml_removedocument @DocHandle; +GO +~~START~~ +varchar#!#date#!#varchar#!#varchar#!#varchar +#!#2024-01-15#!#CUST001#!#Acme Corp#!#123 Business St +~~END~~ + +~~START~~ +varchar#!#varchar#!#varchar#!#int#!#numeric#!#numeric +#!#SKU001#!#Laptop#!#2#!#999.99#!#0.10 +#!#SKU002#!#Mouse#!#5#!#24.99#!#0.05 +~~END~~ + + + + + + + + + +-- Basic example which gives customer, order, product details +DECLARE @DocHandle int; +DECLARE @XmlDocument nvarchar(1000); +SET @XmlDocument = N' + + + + + + + + + + + +'; +EXEC sp_xml_preparedocument @DocHandle OUTPUT, @XmlDocument; +SELECT * +FROM OPENXML (@DocHandle, '/ROOT/Customer', 1) +WITH ( + CustomerID varchar(10), + ContactName varchar(50) +); +SELECT * +FROM OPENXML (@DocHandle, '/ROOT/Customer/Order', 1) +WITH ( + OrderID int, + OrderDate date, + CustomerID varchar(10) '../@CustomerID' +); +SELECT * +FROM OPENXML (@DocHandle, '/ROOT/Customer/Order/Product', 1) +WITH ( + OrderID int '../@OrderID', + ProductID varchar(10), + Quantity int, + Price decimal(10,2) +); +EXEC sp_xml_removedocument @DocHandle; +GO +~~START~~ +varchar#!#varchar +C001#!#John Doe +C002#!#Jane Smith +~~END~~ + +~~START~~ +int#!#date#!#varchar +1001#!#2024-01-15#!#C001 +1002#!#2024-01-16#!#C002 +~~END~~ + +~~START~~ +int#!#varchar#!#int#!#numeric +1001#!#P1#!#5#!#100.00 +1001#!#P2#!#3#!#200.00 +1002#!#P3#!#2#!#150.00 +~~END~~ + + + + + + +-- When table name or colname > 64 bytes +-- Test Case 1: Long table name (> 64 bytes) +INSERT INTO very_long_table_name_that_exceeds_sixty_four_characters_limit_test +VALUES (1, 'Test', 100); +DECLARE @xml_doc INT; +EXEC sp_xml_preparedocument @xml_doc OUTPUT, +''; +SELECT * FROM +OPENXML(@xml_doc, '/root/item') +WITH very_long_table_name_that_exceeds_sixty_four_characters_limit_test; +EXEC sp_xml_removedocument @xml_doc; +GO +~~ROW COUNT: 1~~ + +~~START~~ +int#!#varchar#!#int +1#!#John#!#200 +~~END~~ + + + + + + +-- Test Case 2: Long column names (> 64 bytes) +INSERT INTO test_long_columns VALUES (1, 'Test Value', 999); +DECLARE @xml_doc2 INT; +EXEC sp_xml_preparedocument @xml_doc2 OUTPUT, +' + +'; +SELECT * FROM +OPENXML(@xml_doc2, '/data/record') +WITH test_long_columns; +EXEC sp_xml_removedocument @xml_doc2; +GO +~~ROW COUNT: 1~~ + +~~START~~ +int#!#varchar#!#int +#!##!#456 +~~END~~ + + + + +-- Test Case 3: Explicit column definitions with long names +DECLARE @xml_doc3 INT; +EXEC sp_xml_preparedocument @xml_doc3 OUTPUT, +' + +'; +SELECT * FROM +OPENXML(@xml_doc3, '/items/item') WITH ( + very_long_column_name_that_definitely_exceeds_sixty_four_characters_limit_one VARCHAR(100), + another_extremely_long_column_name_that_exceeds_standard_database_limits_two VARCHAR(100) +); +EXEC sp_xml_removedocument @xml_doc3; +GO +~~START~~ +varchar#!#varchar +#!# +~~END~~ + + + + +-- Test Case 4: Mixed long and short names +DECLARE @xml_doc4 INT; +EXEC sp_xml_preparedocument @xml_doc4 OUTPUT, +' + +'; +SELECT * FROM +OPENXML(@xml_doc4, '/test/row') +WITH mixed_length_names; +EXEC sp_xml_removedocument @xml_doc4; +GO +~~START~~ +int#!#varchar#!#varchar +1#!##!#Short +~~END~~ + + + + + +-- Openxml with table having default constraints +INSERT INTO employee_defaults (name, department, salary) +VALUES ('Test Employee', 'IT', 50000); +DECLARE @xml_doc INT; +EXEC sp_xml_preparedocument @xml_doc OUTPUT, +' + + + +'; +SELECT * FROM +OPENXML(@xml_doc, '/employees/emp') WITH employee_defaults; +EXEC sp_xml_removedocument @xml_doc; +GO +~~ROW COUNT: 1~~ + +~~START~~ +int#!#varchar#!#varchar#!#numeric#!#datetime#!#varchar +#!#John Smith#!#HR#!##!##!# +#!#Jane Doe#!##!#75000.00#!##!# +#!#Bob Wilson#!##!##!##!# +~~END~~ + diff --git a/test/JDBC/input/xml/openxml_with_clause-vu-cleanup.sql b/test/JDBC/input/xml/openxml_with_clause-vu-cleanup.sql new file mode 100644 index 00000000000..52ef558d1ea --- /dev/null +++ b/test/JDBC/input/xml/openxml_with_clause-vu-cleanup.sql @@ -0,0 +1,17 @@ +DROP TABLE test_openxml_table; +GO + +DROP TABLE test_openxml_table_2; +GO + +DROP TABLE very_long_table_name_that_exceeds_sixty_four_characters_limit_test; +GO + +DROP TABLE test_long_columns; +GO + +DROP TABLE mixed_length_names; +GO + +DROP TABLE employee_defaults; +GO \ No newline at end of file diff --git a/test/JDBC/input/xml/openxml_with_clause-vu-prepare.sql b/test/JDBC/input/xml/openxml_with_clause-vu-prepare.sql new file mode 100644 index 00000000000..5f3d3fa5512 --- /dev/null +++ b/test/JDBC/input/xml/openxml_with_clause-vu-prepare.sql @@ -0,0 +1,37 @@ +CREATE TABLE test_openxml_table(oid char(5), date datetime, amount float); +GO + +CREATE TABLE test_openxml_table_2(oid char(5), Date datetime, amount float); +GO + +CREATE TABLE very_long_table_name_that_exceeds_sixty_four_characters_limit_test ( + id INT, + name VARCHAR(50), + value INT +); +GO + +CREATE TABLE test_long_columns ( + very_long_column_name_that_definitely_exceeds_sixty_four_characters_limit_test INT, + another_extremely_long_column_name_exceeding_standard_limits_for_testing VARCHAR(50), + short_col INT +); +GO + +CREATE TABLE mixed_length_names ( + id INT, + extremely_long_column_name_that_exceeds_the_standard_sixty_four_character_limit_for_identifiers VARCHAR(200), + short VARCHAR(50) +); +GO + +CREATE TABLE employee_defaults ( + id INT IDENTITY(1,1) PRIMARY KEY, + name VARCHAR(50) NOT NULL, + department VARCHAR(20) DEFAULT 'Unknown', + salary DECIMAL(10,2) DEFAULT 0.00, + hire_date DATETIME DEFAULT GETDATE(), + status VARCHAR(10) DEFAULT 'Active', + CHECK (salary >= 0) +); +GO \ No newline at end of file diff --git a/test/JDBC/input/xml/openxml_with_clause-vu-verify.sql b/test/JDBC/input/xml/openxml_with_clause-vu-verify.sql index 4ccaac63256..147dcfe6a97 100644 --- a/test/JDBC/input/xml/openxml_with_clause-vu-verify.sql +++ b/test/JDBC/input/xml/openxml_with_clause-vu-verify.sql @@ -200,7 +200,6 @@ EXEC sp_xml_removedocument @idoc; GO -- If tablename is given -CREATE TABLE test_openxml_table(oid char(5), date datetime, amount float); DECLARE @docHandle int; DECLARE @XmlDocument varchar(1000); @@ -227,8 +226,6 @@ FROM OPENXML (@docHandle, '/root/Customer/Order', 1) EXEC sp_xml_removedocument @docHandle; GO -DROP TABLE test_openxml_table; -GO -- If flag value more than 3 DECLARE @XmlDocumentHandle int; @@ -287,7 +284,7 @@ FROM OPENXML (@XmlDocumentHandle, '/ROOT/Customer', 7) EXEC sp_xml_removedocument @XmlDocumentHandle; GO --- colpattern is case sensitive (this gives null) +-- rowpattern is case sensitive (this gives null) DECLARE @XmlDocumentHandle int; DECLARE @XmlDocument nvarchar(1000); SET @XmlDocument = N' @@ -314,4 +311,285 @@ FROM OPENXML (@XmlDocumentHandle, '/root/customer', 4) WITH (CustomerID varchar(10), ContactName varchar(20)); EXEC sp_xml_removedocument @XmlDocumentHandle; -GO \ No newline at end of file +GO + +-- colpattern is case sensitive +DECLARE @DocHandle int; +DECLARE @XmlDocument nvarchar(1000); +SET @XmlDocument = N' + + + + + + + + + + + +'; + +EXEC sp_xml_preparedocument @DocHandle OUTPUT, @XmlDocument; + +SELECT * +FROM OPENXML (@DocHandle, '/ROOT/Customer',1) + WITH (customerid varchar(10) , + contactname varchar(20)); +EXEC sp_xml_removedocument @DocHandle; +GO + +-- negative flag value +DECLARE @XmlDocumentHandle int; +DECLARE @XmlDocument nvarchar(1000); +SET @XmlDocument = N' + + VINET + Paul Henriot + + + + + + + + + + +'; + +EXEC sp_xml_preparedocument @XmlDocumentHandle OUTPUT, @XmlDocument; + +SELECT * +FROM OPENXML (@XmlDocumentHandle, '/ROOT/Customer', -1) + WITH (CustomerID varchar(10), + ContactName varchar(20)); +EXEC sp_xml_removedocument @XmlDocumentHandle; +GO + +-- Mixed attributes +DECLARE @DocHandle int; +DECLARE @XmlDocument nvarchar(1000); +SET @XmlDocument = N' + + The Great Novel + + John + Author + 4.5 + + + Book House + 2023 + 29.99 + + +'; + +EXEC sp_xml_preparedocument @DocHandle OUTPUT, @XmlDocument; + +SELECT * +FROM OPENXML (@DocHandle, '/Library/Book', 2) +WITH ( + ISBN varchar(20), + Category varchar(50), + Title varchar(100) 'Title', + AuthorFirstName varchar(50) 'Author/FirstName', + AuthorLastName varchar(50) 'Author/LastName', + Rating decimal(3,1) 'Author/Rating', + Publisher varchar(50) 'Publication/Publisher', + PublishYear int 'Publication/Year', + Price decimal(10,2) 'Publication/Price', + Currency varchar(3) 'Publication/Price/@currency' +); +EXEC sp_xml_removedocument @DocHandle; +GO + +-- Nested elements +DECLARE @DocHandle int; +DECLARE @XmlDocument nvarchar(2000); +SET @XmlDocument = N' + + + Acme Corp +
123 Business St
+
+ + + Laptop + 2 + 999.99 + 0.10 + + + Mouse + 5 + 24.99 + 0.05 + + +
+
'; + +EXEC sp_xml_preparedocument @DocHandle OUTPUT, @XmlDocument; + +SELECT * +FROM OPENXML (@DocHandle, '/Invoices/Invoice', 2) +WITH ( + InvoiceID varchar(10), + InvoiceDate date '@Date', + CustomerID varchar(10) 'Customer/@ID', + CustomerName varchar(50) 'Customer/Name', + CustomerAddress varchar(100) 'Customer/Address' +); + +SELECT * +FROM OPENXML (@DocHandle, '/Invoices/Invoice/Items/Item', 2) +WITH ( + InvoiceID varchar(10) '../../../@InvoiceID', + SKU varchar(10) '@SKU', + Description varchar(100) 'Description', + Quantity int 'Quantity', + UnitPrice decimal(10,2) 'UnitPrice', + Discount decimal(4,2) 'Discount' +); + +EXEC sp_xml_removedocument @DocHandle; +GO + +-- Basic example which gives customer, order, product details +DECLARE @DocHandle int; +DECLARE @XmlDocument nvarchar(1000); +SET @XmlDocument = N' + + + + + + + + + + + +'; + +EXEC sp_xml_preparedocument @DocHandle OUTPUT, @XmlDocument; + + +SELECT * +FROM OPENXML (@DocHandle, '/ROOT/Customer', 1) +WITH ( + CustomerID varchar(10), + ContactName varchar(50) +); + +SELECT * +FROM OPENXML (@DocHandle, '/ROOT/Customer/Order', 1) +WITH ( + OrderID int, + OrderDate date, + CustomerID varchar(10) '../@CustomerID' +); + + +SELECT * +FROM OPENXML (@DocHandle, '/ROOT/Customer/Order/Product', 1) +WITH ( + OrderID int '../@OrderID', + ProductID varchar(10), + Quantity int, + Price decimal(10,2) +); + +EXEC sp_xml_removedocument @DocHandle; +GO + +-- When table name or colname > 64 bytes + +-- Test Case 1: Long table name (> 64 bytes) +INSERT INTO very_long_table_name_that_exceeds_sixty_four_characters_limit_test +VALUES (1, 'Test', 100); + +DECLARE @xml_doc INT; +EXEC sp_xml_preparedocument @xml_doc OUTPUT, +''; + +SELECT * FROM +OPENXML(@xml_doc, '/root/item') +WITH very_long_table_name_that_exceeds_sixty_four_characters_limit_test; + +EXEC sp_xml_removedocument @xml_doc; +GO + +-- Test Case 2: Long column names (> 64 bytes) +INSERT INTO test_long_columns VALUES (1, 'Test Value', 999); + +DECLARE @xml_doc2 INT; +EXEC sp_xml_preparedocument @xml_doc2 OUTPUT, +' + +'; + + +SELECT * FROM +OPENXML(@xml_doc2, '/data/record') +WITH test_long_columns; + +EXEC sp_xml_removedocument @xml_doc2; +GO + +-- Test Case 3: Explicit column definitions with long names +DECLARE @xml_doc3 INT; +EXEC sp_xml_preparedocument @xml_doc3 OUTPUT, +' + +'; + +SELECT * FROM +OPENXML(@xml_doc3, '/items/item') WITH ( + very_long_column_name_that_definitely_exceeds_sixty_four_characters_limit_one VARCHAR(100), + another_extremely_long_column_name_that_exceeds_standard_database_limits_two VARCHAR(100) +); + +EXEC sp_xml_removedocument @xml_doc3; +GO + +-- Test Case 4: Mixed long and short names +DECLARE @xml_doc4 INT; +EXEC sp_xml_preparedocument @xml_doc4 OUTPUT, +' + +'; + +SELECT * FROM +OPENXML(@xml_doc4, '/test/row') +WITH mixed_length_names; + +EXEC sp_xml_removedocument @xml_doc4; +GO + +-- Openxml with table having default constraints +INSERT INTO employee_defaults (name, department, salary) +VALUES ('Test Employee', 'IT', 50000); + +DECLARE @xml_doc INT; +EXEC sp_xml_preparedocument @xml_doc OUTPUT, +' + + + +'; + +SELECT * FROM +OPENXML(@xml_doc, '/employees/emp') WITH employee_defaults; + +EXEC sp_xml_removedocument @xml_doc; +GO From 4c1a102b60ccf059236dbd7fa88f0615b9022837 Mon Sep 17 00:00:00 2001 From: Harsh Dubey Date: Wed, 25 Jun 2025 10:49:54 +0000 Subject: [PATCH 18/40] Added testcases of cross/outer apply Signed-off-by: Harsh Dubey --- .../babelfishpg_tsql/src/extendedproperty.c | 3 +- .../babelfishpg_tsql/src/extendedproperty.h | 1 + contrib/babelfishpg_tsql/src/hooks.c | 55 +++- .../openxml_with_clause-vu-cleanup.out | 9 + .../openxml_with_clause-vu-prepare.out | 24 ++ .../openxml_with_clause-vu-verify.out | 310 +++++++++++++++++- .../xml/openxml_with_clause-vu-cleanup.sql | 9 + .../xml/openxml_with_clause-vu-prepare.sql | 24 ++ .../xml/openxml_with_clause-vu-verify.sql | 239 ++++++++++++++ 9 files changed, 653 insertions(+), 21 deletions(-) diff --git a/contrib/babelfishpg_tsql/src/extendedproperty.c b/contrib/babelfishpg_tsql/src/extendedproperty.c index ad2719e1a89..2e1e22ffa04 100644 --- a/contrib/babelfishpg_tsql/src/extendedproperty.c +++ b/contrib/babelfishpg_tsql/src/extendedproperty.c @@ -71,7 +71,6 @@ static void init_scan_key(ScanKeyData *scanKey, static void sp_execextended_property(PG_FUNCTION_ARGS, ExtendedPropertyProc proc); static bool get_extended_property_from_tuple(Relation relation, HeapTuple tuple, Datum *values, bool *nulls, int len); -static char* get_value_by_name_from_array(ArrayType *array, const char *name); static void init_scan_key(ScanKeyData *scanKey, @@ -923,7 +922,7 @@ fn_listextendedproperty(PG_FUNCTION_ARGS) extern const char *ATTOPTION_BBF_ORIGINAL_TABLE_NAME; extern const char *ATTOPTION_BBF_ORIGINAL_NAME; -static char* +char* get_value_by_name_from_array(ArrayType *array, const char *name) { int i; diff --git a/contrib/babelfishpg_tsql/src/extendedproperty.h b/contrib/babelfishpg_tsql/src/extendedproperty.h index 99ccd7a4c4b..b68e4188c5c 100644 --- a/contrib/babelfishpg_tsql/src/extendedproperty.h +++ b/contrib/babelfishpg_tsql/src/extendedproperty.h @@ -16,6 +16,7 @@ typedef enum ExtendedPropertyType } ExtendedPropertyType; extern const char *const ExtendedPropertyTypeNames[]; +extern char *get_value_by_name_from_array(ArrayType *array, const char *name); extern void delete_extended_property(int16 db_id, const char *type, diff --git a/contrib/babelfishpg_tsql/src/hooks.c b/contrib/babelfishpg_tsql/src/hooks.c index 9b0febf7bb7..64af0505f26 100644 --- a/contrib/babelfishpg_tsql/src/hooks.c +++ b/contrib/babelfishpg_tsql/src/hooks.c @@ -88,6 +88,7 @@ #include "tsql_analyze.h" #include "table_variable_mvcc.h" #include "bbf_parallel_query.h" +#include "extendedproperty.h" #define TDS_NUMERIC_MAX_PRECISION 38 @@ -6553,9 +6554,11 @@ fetch_table_schema(RangeVar *relation, Node *flag) if (relation != NULL) { - Relation rel; - TupleDesc tupdesc; - int i; + Relation rel; + ScanKeyData skey[1]; + SysScanDesc scan; + HeapTuple tuple; + Relation attrel; /* Open the relation to get its schema */ rel = relation_openrv(relation, AccessShareLock); @@ -6568,21 +6571,45 @@ fetch_table_schema(RangeVar *relation, Node *flag) relation->relname))); } - /* Get the tuple descriptor which contains column information */ - tupdesc = RelationGetDescr(rel); + /* Open pg_attribute catalog */ + attrel = table_open(AttributeRelationId, AccessShareLock); + + /* Set up scan key for this relation */ + ScanKeyInit(&skey[0], + Anum_pg_attribute_attrelid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(RelationGetRelid(rel))); + + scan = systable_beginscan(attrel, AttributeRelidNumIndexId, true, + NULL, 1, skey); - /* Create RangeTableFuncCol nodes from the table's columns */ - for (i = 0; i < tupdesc->natts; i++) + /* Process each column */ + while (HeapTupleIsValid(tuple = systable_getnext(scan))) { - Form_pg_attribute att = TupleDescAttr(tupdesc, i); + Form_pg_attribute att = (Form_pg_attribute) GETSTRUCT(tuple); RangeTableFuncCol *fc; char *colname; - - /* Skip dropped columns */ - if (att->attisdropped) + ArrayType *attoptions; + Datum datum; + bool isnull; + + /* Skip dropped columns, system columns and identity columns */ + if (att->attisdropped || att->attnum <= 0 || att->attidentity) continue; - - colname = NameStr(att->attname); + + /* Get original column name from attoptions */ + datum = heap_getattr(tuple, Anum_pg_attribute_attoptions, + RelationGetDescr(attrel), &isnull); + + if (!isnull) + { + attoptions = DatumGetArrayTypeP(datum); + colname = get_value_by_name_from_array(attoptions, ATTOPTION_BBF_ORIGINAL_NAME); + } + else + { + colname = NameStr(att->attname); + } /* Create a column definition */ fc = makeNode(RangeTableFuncCol); @@ -6599,6 +6626,8 @@ fetch_table_schema(RangeVar *relation, Node *flag) columns = lappend(columns, fc); } + systable_endscan(scan); + table_close(attrel, AccessShareLock); relation_close(rel, AccessShareLock); } diff --git a/test/JDBC/expected/openxml_with_clause-vu-cleanup.out b/test/JDBC/expected/openxml_with_clause-vu-cleanup.out index 7cdda0c3e79..421b49cf82a 100644 --- a/test/JDBC/expected/openxml_with_clause-vu-cleanup.out +++ b/test/JDBC/expected/openxml_with_clause-vu-cleanup.out @@ -15,3 +15,12 @@ GO DROP TABLE employee_defaults; GO + +DROP TABLE person_table; +GO + +DROP TABLE regions; +GO + +DROP TABLE Employee_Details; +GO diff --git a/test/JDBC/expected/openxml_with_clause-vu-prepare.out b/test/JDBC/expected/openxml_with_clause-vu-prepare.out index 343c997fe56..b676342b1e8 100644 --- a/test/JDBC/expected/openxml_with_clause-vu-prepare.out +++ b/test/JDBC/expected/openxml_with_clause-vu-prepare.out @@ -35,3 +35,27 @@ CREATE TABLE employee_defaults ( CHECK (salary >= 0) ); GO + +CREATE TABLE person_table ( + id INT, + name VARCHAR(50), + age INT +); +GO + +CREATE TABLE regions (region_id INT, region_name VARCHAR(50)); +GO + +-- table having default constraints +CREATE TABLE Employee_Details ( + EmployeeID INT IDENTITY(1000,1) PRIMARY KEY, + FirstName VARCHAR(50) NOT NULL, + LastName VARCHAR(50) NOT NULL, + Email VARCHAR(100) UNIQUE CHECK (Email LIKE '%@%.%'), + Phone VARCHAR(15) UNIQUE CHECK (Phone LIKE '[0-9][0-9][0-9]-[0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]'), + JoinDate DATE DEFAULT GETDATE(), + Status VARCHAR(20) DEFAULT 'Active' CHECK (Status IN ('Active', 'Inactive', 'On Leave')), + Salary DECIMAL(10,2) CHECK (Salary >= 0), + Department VARCHAR(50) CHECK (Department IN ('IT', 'HR', 'Finance', 'Marketing', 'Sales')) +); +GO diff --git a/test/JDBC/expected/openxml_with_clause-vu-verify.out b/test/JDBC/expected/openxml_with_clause-vu-verify.out index 538d20b4c30..1036ee53955 100644 --- a/test/JDBC/expected/openxml_with_clause-vu-verify.out +++ b/test/JDBC/expected/openxml_with_clause-vu-verify.out @@ -668,7 +668,7 @@ GO ~~START~~ int#!#varchar#!#int -#!##!#456 +123#!#Long Value#!#456 ~~END~~ @@ -710,7 +710,7 @@ EXEC sp_xml_removedocument @xml_doc4; GO ~~START~~ int#!#varchar#!#varchar -1#!##!#Short +1#!#Long Value Test#!#Short ~~END~~ @@ -734,9 +734,307 @@ GO ~~ROW COUNT: 1~~ ~~START~~ -int#!#varchar#!#varchar#!#numeric#!#datetime#!#varchar -#!#John Smith#!#HR#!##!##!# -#!#Jane Doe#!##!#75000.00#!##!# -#!#Bob Wilson#!##!##!##!# +varchar#!#varchar#!#numeric#!#datetime#!#varchar +John Smith#!#HR#!##!##!# +Jane Doe#!##!#75000.00#!##!# +Bob Wilson#!##!##!##!# +~~END~~ + + +-- Test with empty XML document +DECLARE @DocHandle int; +EXEC sp_xml_preparedocument @DocHandle OUTPUT, @DocHandle; +SELECT * +FROM OPENXML (@DocHandle, '/', 1) +WITH ( + CustomerID varchar(10), + ContactName varchar(50) +); +EXEC sp_xml_removedocument @DocHandle; +GO +~~START~~ +varchar#!#varchar +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Could not find prepared statement with handle 43)~~ + + + + + +-- CROSS APPLY with openxml +DECLARE @DocHandle int; +DECLARE @XmlDocument nvarchar(1000); +SET @XmlDocument = N' + + + + + + + +'; +EXEC sp_xml_preparedocument @DocHandle OUTPUT, @XmlDocument; +SELECT + c.CustomerID, + c.CustomerName, + o.OrderID, + o.OrderDate +FROM + OPENXML(@DocHandle, '/Customers/Customer', 2) + WITH ( + CustomerID int '@ID', + CustomerName varchar(50) '@Name' + ) c +CROSS APPLY + OPENXML(@DocHandle, '/Customers/Customer', 2) + WITH ( + OrderID int '@ID', + OrderDate date '@Date' + ) o; +EXEC sp_xml_removedocument @DocHandle; +GO +~~START~~ +int#!#varchar#!#int#!#date +1#!#John#!#1#!# +1#!#John#!#2#!# +2#!#Jane#!#1#!# +2#!#Jane#!#2#!# +~~END~~ + + + + + +-- cross apply for different row patterns +DECLARE @DocHandle int; +DECLARE @XmlDocument nvarchar(1000); +SET @XmlDocument = N' + + + + + + + +'; +EXEC sp_xml_preparedocument @DocHandle OUTPUT, @XmlDocument; +SELECT + c.CustomerID, + c.CustomerName, + o.OrderID, + o.OrderDate +FROM + OPENXML(@DocHandle, '/Customers/Customer', 2) + WITH ( + CustomerID int '@ID', + CustomerName varchar(50) '@Name' + ) c +CROSS APPLY + OPENXML(@DocHandle, + concat('/Customers/Customer[@ID=', c.CustomerID, ']/Order'), + 2) + WITH ( + OrderID int '@ID', + OrderDate date '@Date' + ) o; +EXEC sp_xml_removedocument @DocHandle; +GO +~~START~~ +int#!#varchar#!#int#!#date +1#!#John#!#1#!#2024-01-01 +1#!#John#!#2#!#2024-01-02 +2#!#Jane#!#3#!#2024-01-03 +~~END~~ + + +-- cross apply for different row patterns +DECLARE @DocHandle int; +DECLARE @XmlDocument nvarchar(1000); +SET @XmlDocument = N''; +EXEC sp_xml_preparedocument @DocHandle OUTPUT, @XmlDocument; +SELECT + c.CustomerID, + c.CustomerName, + o.OrderID, + o.OrderDate +FROM + OPENXML(@DocHandle, '/Customers/Customer', 2) + WITH ( + CustomerID int '@ID', + CustomerName varchar(50) '@Name' + ) c +CROSS APPLY + OPENXML(@DocHandle, + concat('/Customers/Customer[@ID=', c.CustomerID, ']/Order'), + 2) + WITH ( + OrderID int '@ID', + OrderDate date '@Date' + ) o; +EXEC sp_xml_removedocument @DocHandle; +GO +~~START~~ +int#!#varchar#!#int#!#date +~~END~~ + + + + + +-- Basic CROSS APPLY with OPENXML using table reference +INSERT INTO person_table VALUES (1, 'John', 25), (2, 'Jane', 30); +DECLARE @xml_doc INT; +EXEC sp_xml_preparedocument @xml_doc OUTPUT, ''; +SELECT * FROM +(SELECT 1 as id) t +CROSS APPLY OPENXML(@xml_doc, '/root/person') WITH person_table; +EXEC sp_xml_removedocument @xml_doc; +GO +~~ROW COUNT: 2~~ + +~~START~~ +int#!#int#!#varchar#!#int +1#!#1#!#John#!# +1#!#2#!#Jane#!# +~~END~~ + + + + +-- OUTER APPLY +DECLARE @xml_doc2 INT; +EXEC sp_xml_preparedocument @xml_doc2 OUTPUT, +' + + + + + +'; +SELECT + c.customer_id, + c.customer_name, + o.order_id, + o.amount +FROM + OPENXML(@xml_doc2, '/data/customer', 1) WITH ( + customer_id INT, + customer_name VARCHAR(50) + ) c +OUTER APPLY + OPENXML(@xml_doc2, '/data/order', 1) WITH ( + cust_id INT, + order_id INT, + amount DECIMAL(10,2) + ) o; +EXEC sp_xml_removedocument @xml_doc2; +GO +~~START~~ +int#!#varchar#!#int#!#numeric +#!##!#100#!#500.00 +#!##!#101#!#300.00 +#!##!#102#!#200.00 +#!##!#100#!#500.00 +#!##!#101#!#300.00 +#!##!#102#!#200.00 +~~END~~ + + + + + + + + + + +-- Base table with outer apply openxml +INSERT INTO regions VALUES (1, 'North'), (2, 'South'), (3, 'East'), (4, 'West'); +DECLARE @xml_doc3 INT; +EXEC sp_xml_preparedocument @xml_doc3 OUTPUT, +' + + + + + + + +'; +SELECT + r.region_id, + r.region_name, + s.amount, + s.product +FROM + regions r +OUTER APPLY + OPENXML(@xml_doc3, '/sales/region/sale', 2) WITH ( + region_id INT '../@id', + amount DECIMAL(10,2), + product VARCHAR(50) + ) s +WHERE s.region_id = r.region_id OR s.region_id IS NULL; +EXEC sp_xml_removedocument @xml_doc3; +-- table having default constraints +DECLARE @DocHandle int; +DECLARE @XmlDocument nvarchar(max); +SET @XmlDocument = N' + + + 1001 + John + Doe + john.doe@company.com + 123-456-7890 + 2024-01-15 + Active + 50000.00 + IT + + + 1002 + Jane + Smith + jane.smith@company.com + 234-567-8901 + 2024-01-16 + Active + 60000.00 + HR + + + 1003 + Mike + Johnson + mike.j@company.com + 345-678-9012 + 2024-01-17 + On Leave + 55000.00 + Finance + +'; +EXEC sp_xml_preparedocument @DocHandle OUTPUT, @XmlDocument; +SELECT * +FROM OPENXML(@DocHandle, '/Employees/Employee' , 2) +WITH Employee_Details; +EXEC sp_xml_removedocument @DocHandle; +GO +~~ROW COUNT: 4~~ + +~~START~~ +int#!#varchar#!#numeric#!#varchar +1#!#North#!##!# +1#!#North#!##!# +3#!#East#!##!# +~~END~~ + +~~START~~ +varchar#!#varchar#!#varchar#!#varchar#!#date#!#varchar#!#numeric#!#varchar +John#!#Doe#!#john.doe@company.com#!#123-456-7890#!#2024-01-15#!#Active#!#50000.00#!#IT +Jane#!#Smith#!#jane.smith@company.com#!#234-567-8901#!#2024-01-16#!#Active#!#60000.00#!#HR +Mike#!#Johnson#!#mike.j@company.com#!#345-678-9012#!#2024-01-17#!#On Leave#!#55000.00#!#Finance ~~END~~ diff --git a/test/JDBC/input/xml/openxml_with_clause-vu-cleanup.sql b/test/JDBC/input/xml/openxml_with_clause-vu-cleanup.sql index 52ef558d1ea..22b71cfa281 100644 --- a/test/JDBC/input/xml/openxml_with_clause-vu-cleanup.sql +++ b/test/JDBC/input/xml/openxml_with_clause-vu-cleanup.sql @@ -14,4 +14,13 @@ DROP TABLE mixed_length_names; GO DROP TABLE employee_defaults; +GO + +DROP TABLE person_table; +GO + +DROP TABLE regions; +GO + +DROP TABLE Employee_Details; GO \ No newline at end of file diff --git a/test/JDBC/input/xml/openxml_with_clause-vu-prepare.sql b/test/JDBC/input/xml/openxml_with_clause-vu-prepare.sql index 5f3d3fa5512..45303a5f2b4 100644 --- a/test/JDBC/input/xml/openxml_with_clause-vu-prepare.sql +++ b/test/JDBC/input/xml/openxml_with_clause-vu-prepare.sql @@ -34,4 +34,28 @@ CREATE TABLE employee_defaults ( status VARCHAR(10) DEFAULT 'Active', CHECK (salary >= 0) ); +GO + +CREATE TABLE person_table ( + id INT, + name VARCHAR(50), + age INT +); +GO + +CREATE TABLE regions (region_id INT, region_name VARCHAR(50)); +GO + +-- table having default constraints +CREATE TABLE Employee_Details ( + EmployeeID INT IDENTITY(1000,1) PRIMARY KEY, + FirstName VARCHAR(50) NOT NULL, + LastName VARCHAR(50) NOT NULL, + Email VARCHAR(100) UNIQUE CHECK (Email LIKE '%@%.%'), + Phone VARCHAR(15) UNIQUE CHECK (Phone LIKE '[0-9][0-9][0-9]-[0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]'), + JoinDate DATE DEFAULT GETDATE(), + Status VARCHAR(20) DEFAULT 'Active' CHECK (Status IN ('Active', 'Inactive', 'On Leave')), + Salary DECIMAL(10,2) CHECK (Salary >= 0), + Department VARCHAR(50) CHECK (Department IN ('IT', 'HR', 'Finance', 'Marketing', 'Sales')) +); GO \ No newline at end of file diff --git a/test/JDBC/input/xml/openxml_with_clause-vu-verify.sql b/test/JDBC/input/xml/openxml_with_clause-vu-verify.sql index 147dcfe6a97..9af54dc31d0 100644 --- a/test/JDBC/input/xml/openxml_with_clause-vu-verify.sql +++ b/test/JDBC/input/xml/openxml_with_clause-vu-verify.sql @@ -593,3 +593,242 @@ OPENXML(@xml_doc, '/employees/emp') WITH employee_defaults; EXEC sp_xml_removedocument @xml_doc; GO + +-- Test with empty XML document +DECLARE @DocHandle int; +EXEC sp_xml_preparedocument @DocHandle OUTPUT, @DocHandle; +SELECT * +FROM OPENXML (@DocHandle, '/', 1) +WITH ( + CustomerID varchar(10), + ContactName varchar(50) +); +EXEC sp_xml_removedocument @DocHandle; +GO + +-- CROSS APPLY with openxml +DECLARE @DocHandle int; +DECLARE @XmlDocument nvarchar(1000); +SET @XmlDocument = N' + + + + + + + +'; + +EXEC sp_xml_preparedocument @DocHandle OUTPUT, @XmlDocument; + +SELECT + c.CustomerID, + c.CustomerName, + o.OrderID, + o.OrderDate +FROM + OPENXML(@DocHandle, '/Customers/Customer', 2) + WITH ( + CustomerID int '@ID', + CustomerName varchar(50) '@Name' + ) c +CROSS APPLY + OPENXML(@DocHandle, '/Customers/Customer', 2) + WITH ( + OrderID int '@ID', + OrderDate date '@Date' + ) o; + +EXEC sp_xml_removedocument @DocHandle; +GO + +-- cross apply for different row patterns +DECLARE @DocHandle int; +DECLARE @XmlDocument nvarchar(1000); +SET @XmlDocument = N' + + + + + + + +'; + +EXEC sp_xml_preparedocument @DocHandle OUTPUT, @XmlDocument; + +SELECT + c.CustomerID, + c.CustomerName, + o.OrderID, + o.OrderDate +FROM + OPENXML(@DocHandle, '/Customers/Customer', 2) + WITH ( + CustomerID int '@ID', + CustomerName varchar(50) '@Name' + ) c +CROSS APPLY + OPENXML(@DocHandle, + concat('/Customers/Customer[@ID=', c.CustomerID, ']/Order'), + 2) + WITH ( + OrderID int '@ID', + OrderDate date '@Date' + ) o; + +EXEC sp_xml_removedocument @DocHandle; +GO + +-- cross apply for different row patterns +DECLARE @DocHandle int; +DECLARE @XmlDocument nvarchar(1000); +SET @XmlDocument = N''; +EXEC sp_xml_preparedocument @DocHandle OUTPUT, @XmlDocument; +SELECT + c.CustomerID, + c.CustomerName, + o.OrderID, + o.OrderDate +FROM + OPENXML(@DocHandle, '/Customers/Customer', 2) + WITH ( + CustomerID int '@ID', + CustomerName varchar(50) '@Name' + ) c +CROSS APPLY + OPENXML(@DocHandle, + concat('/Customers/Customer[@ID=', c.CustomerID, ']/Order'), + 2) + WITH ( + OrderID int '@ID', + OrderDate date '@Date' + ) o; +EXEC sp_xml_removedocument @DocHandle; +GO + +-- Basic CROSS APPLY with OPENXML using table reference +INSERT INTO person_table VALUES (1, 'John', 25), (2, 'Jane', 30); + +DECLARE @xml_doc INT; +EXEC sp_xml_preparedocument @xml_doc OUTPUT, ''; + +SELECT * FROM +(SELECT 1 as id) t +CROSS APPLY OPENXML(@xml_doc, '/root/person') WITH person_table; + +EXEC sp_xml_removedocument @xml_doc; +GO + +-- OUTER APPLY +DECLARE @xml_doc2 INT; +EXEC sp_xml_preparedocument @xml_doc2 OUTPUT, +' + + + + + +'; + +SELECT + c.customer_id, + c.customer_name, + o.order_id, + o.amount +FROM + OPENXML(@xml_doc2, '/data/customer', 1) WITH ( + customer_id INT, + customer_name VARCHAR(50) + ) c +OUTER APPLY + OPENXML(@xml_doc2, '/data/order', 1) WITH ( + cust_id INT, + order_id INT, + amount DECIMAL(10,2) + ) o; + +EXEC sp_xml_removedocument @xml_doc2; +GO + +-- Base table with outer apply openxml +INSERT INTO regions VALUES (1, 'North'), (2, 'South'), (3, 'East'), (4, 'West'); + +DECLARE @xml_doc3 INT; +EXEC sp_xml_preparedocument @xml_doc3 OUTPUT, +' + + + + + + + +'; + +SELECT + r.region_id, + r.region_name, + s.amount, + s.product +FROM + regions r +OUTER APPLY + OPENXML(@xml_doc3, '/sales/region/sale', 2) WITH ( + region_id INT '../@id', + amount DECIMAL(10,2), + product VARCHAR(50) + ) s +WHERE s.region_id = r.region_id OR s.region_id IS NULL; + +EXEC sp_xml_removedocument @xml_doc3; + +-- table having default constraints +DECLARE @DocHandle int; +DECLARE @XmlDocument nvarchar(max); + +SET @XmlDocument = N' + + + 1001 + John + Doe + john.doe@company.com + 123-456-7890 + 2024-01-15 + Active + 50000.00 + IT + + + 1002 + Jane + Smith + jane.smith@company.com + 234-567-8901 + 2024-01-16 + Active + 60000.00 + HR + + + 1003 + Mike + Johnson + mike.j@company.com + 345-678-9012 + 2024-01-17 + On Leave + 55000.00 + Finance + +'; + +EXEC sp_xml_preparedocument @DocHandle OUTPUT, @XmlDocument; + +SELECT * +FROM OPENXML(@DocHandle, '/Employees/Employee' , 2) +WITH Employee_Details; + +EXEC sp_xml_removedocument @DocHandle; +GO \ No newline at end of file From 00e19184ad21d666b08901cf64bd6aa2cade8026 Mon Sep 17 00:00:00 2001 From: Harsh Dubey Date: Wed, 25 Jun 2025 12:18:48 +0000 Subject: [PATCH 19/40] fixed not null constraint in the test plan Signed-off-by: Harsh Dubey --- test/JDBC/expected/openxml_with_clause-vu-prepare.out | 4 ++-- test/JDBC/input/xml/openxml_with_clause-vu-prepare.sql | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/test/JDBC/expected/openxml_with_clause-vu-prepare.out b/test/JDBC/expected/openxml_with_clause-vu-prepare.out index b676342b1e8..9d1bcb53b1f 100644 --- a/test/JDBC/expected/openxml_with_clause-vu-prepare.out +++ b/test/JDBC/expected/openxml_with_clause-vu-prepare.out @@ -51,8 +51,8 @@ CREATE TABLE Employee_Details ( EmployeeID INT IDENTITY(1000,1) PRIMARY KEY, FirstName VARCHAR(50) NOT NULL, LastName VARCHAR(50) NOT NULL, - Email VARCHAR(100) UNIQUE CHECK (Email LIKE '%@%.%'), - Phone VARCHAR(15) UNIQUE CHECK (Phone LIKE '[0-9][0-9][0-9]-[0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]'), + Email VARCHAR(100) NOT NULL UNIQUE CHECK (Email LIKE '%@%.%'), + Phone VARCHAR(15) NOT NULL UNIQUE CHECK (Phone LIKE '[0-9][0-9][0-9]-[0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]'), JoinDate DATE DEFAULT GETDATE(), Status VARCHAR(20) DEFAULT 'Active' CHECK (Status IN ('Active', 'Inactive', 'On Leave')), Salary DECIMAL(10,2) CHECK (Salary >= 0), diff --git a/test/JDBC/input/xml/openxml_with_clause-vu-prepare.sql b/test/JDBC/input/xml/openxml_with_clause-vu-prepare.sql index 45303a5f2b4..3a4dedeeb1e 100644 --- a/test/JDBC/input/xml/openxml_with_clause-vu-prepare.sql +++ b/test/JDBC/input/xml/openxml_with_clause-vu-prepare.sql @@ -51,8 +51,8 @@ CREATE TABLE Employee_Details ( EmployeeID INT IDENTITY(1000,1) PRIMARY KEY, FirstName VARCHAR(50) NOT NULL, LastName VARCHAR(50) NOT NULL, - Email VARCHAR(100) UNIQUE CHECK (Email LIKE '%@%.%'), - Phone VARCHAR(15) UNIQUE CHECK (Phone LIKE '[0-9][0-9][0-9]-[0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]'), + Email VARCHAR(100) NOT NULL UNIQUE CHECK (Email LIKE '%@%.%'), + Phone VARCHAR(15) NOT NULL UNIQUE CHECK (Phone LIKE '[0-9][0-9][0-9]-[0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]'), JoinDate DATE DEFAULT GETDATE(), Status VARCHAR(20) DEFAULT 'Active' CHECK (Status IN ('Active', 'Inactive', 'On Leave')), Salary DECIMAL(10,2) CHECK (Salary >= 0), From c2bc3559ba719c2035691475a46243f5af2e9221 Mon Sep 17 00:00:00 2001 From: Harsh Dubey Date: Wed, 25 Jun 2025 14:38:40 +0000 Subject: [PATCH 20/40] Fixed the expected file of openxml tests Signed-off-by: Harsh Dubey --- .../openxml_with_clause-vu-cleanup.out | 3 - .../openxml_with_clause-vu-prepare.out | 14 ----- .../openxml_with_clause-vu-verify.out | 55 ------------------- .../xml/openxml_with_clause-vu-cleanup.sql | 3 - .../xml/openxml_with_clause-vu-prepare.sql | 14 ----- .../xml/openxml_with_clause-vu-verify.sql | 50 +---------------- 6 files changed, 1 insertion(+), 138 deletions(-) diff --git a/test/JDBC/expected/openxml_with_clause-vu-cleanup.out b/test/JDBC/expected/openxml_with_clause-vu-cleanup.out index 421b49cf82a..1b4137b427c 100644 --- a/test/JDBC/expected/openxml_with_clause-vu-cleanup.out +++ b/test/JDBC/expected/openxml_with_clause-vu-cleanup.out @@ -21,6 +21,3 @@ GO DROP TABLE regions; GO - -DROP TABLE Employee_Details; -GO diff --git a/test/JDBC/expected/openxml_with_clause-vu-prepare.out b/test/JDBC/expected/openxml_with_clause-vu-prepare.out index 9d1bcb53b1f..a1946dd0a00 100644 --- a/test/JDBC/expected/openxml_with_clause-vu-prepare.out +++ b/test/JDBC/expected/openxml_with_clause-vu-prepare.out @@ -45,17 +45,3 @@ GO CREATE TABLE regions (region_id INT, region_name VARCHAR(50)); GO - --- table having default constraints -CREATE TABLE Employee_Details ( - EmployeeID INT IDENTITY(1000,1) PRIMARY KEY, - FirstName VARCHAR(50) NOT NULL, - LastName VARCHAR(50) NOT NULL, - Email VARCHAR(100) NOT NULL UNIQUE CHECK (Email LIKE '%@%.%'), - Phone VARCHAR(15) NOT NULL UNIQUE CHECK (Phone LIKE '[0-9][0-9][0-9]-[0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]'), - JoinDate DATE DEFAULT GETDATE(), - Status VARCHAR(20) DEFAULT 'Active' CHECK (Status IN ('Active', 'Inactive', 'On Leave')), - Salary DECIMAL(10,2) CHECK (Salary >= 0), - Department VARCHAR(50) CHECK (Department IN ('IT', 'HR', 'Finance', 'Marketing', 'Sales')) -); -GO diff --git a/test/JDBC/expected/openxml_with_clause-vu-verify.out b/test/JDBC/expected/openxml_with_clause-vu-verify.out index 1036ee53955..c9a79bcbb8d 100644 --- a/test/JDBC/expected/openxml_with_clause-vu-verify.out +++ b/test/JDBC/expected/openxml_with_clause-vu-verify.out @@ -944,11 +944,6 @@ int#!#varchar#!#int#!#numeric - - - - - -- Base table with outer apply openxml INSERT INTO regions VALUES (1, 'North'), (2, 'South'), (3, 'East'), (4, 'West'); DECLARE @xml_doc3 INT; @@ -977,50 +972,6 @@ OUTER APPLY ) s WHERE s.region_id = r.region_id OR s.region_id IS NULL; EXEC sp_xml_removedocument @xml_doc3; --- table having default constraints -DECLARE @DocHandle int; -DECLARE @XmlDocument nvarchar(max); -SET @XmlDocument = N' - - - 1001 - John - Doe - john.doe@company.com - 123-456-7890 - 2024-01-15 - Active - 50000.00 - IT - - - 1002 - Jane - Smith - jane.smith@company.com - 234-567-8901 - 2024-01-16 - Active - 60000.00 - HR - - - 1003 - Mike - Johnson - mike.j@company.com - 345-678-9012 - 2024-01-17 - On Leave - 55000.00 - Finance - -'; -EXEC sp_xml_preparedocument @DocHandle OUTPUT, @XmlDocument; -SELECT * -FROM OPENXML(@DocHandle, '/Employees/Employee' , 2) -WITH Employee_Details; -EXEC sp_xml_removedocument @DocHandle; GO ~~ROW COUNT: 4~~ @@ -1031,10 +982,4 @@ int#!#varchar#!#numeric#!#varchar 3#!#East#!##!# ~~END~~ -~~START~~ -varchar#!#varchar#!#varchar#!#varchar#!#date#!#varchar#!#numeric#!#varchar -John#!#Doe#!#john.doe@company.com#!#123-456-7890#!#2024-01-15#!#Active#!#50000.00#!#IT -Jane#!#Smith#!#jane.smith@company.com#!#234-567-8901#!#2024-01-16#!#Active#!#60000.00#!#HR -Mike#!#Johnson#!#mike.j@company.com#!#345-678-9012#!#2024-01-17#!#On Leave#!#55000.00#!#Finance -~~END~~ diff --git a/test/JDBC/input/xml/openxml_with_clause-vu-cleanup.sql b/test/JDBC/input/xml/openxml_with_clause-vu-cleanup.sql index 22b71cfa281..40e755efb27 100644 --- a/test/JDBC/input/xml/openxml_with_clause-vu-cleanup.sql +++ b/test/JDBC/input/xml/openxml_with_clause-vu-cleanup.sql @@ -20,7 +20,4 @@ DROP TABLE person_table; GO DROP TABLE regions; -GO - -DROP TABLE Employee_Details; GO \ No newline at end of file diff --git a/test/JDBC/input/xml/openxml_with_clause-vu-prepare.sql b/test/JDBC/input/xml/openxml_with_clause-vu-prepare.sql index 3a4dedeeb1e..a1946dd0a00 100644 --- a/test/JDBC/input/xml/openxml_with_clause-vu-prepare.sql +++ b/test/JDBC/input/xml/openxml_with_clause-vu-prepare.sql @@ -45,17 +45,3 @@ GO CREATE TABLE regions (region_id INT, region_name VARCHAR(50)); GO - --- table having default constraints -CREATE TABLE Employee_Details ( - EmployeeID INT IDENTITY(1000,1) PRIMARY KEY, - FirstName VARCHAR(50) NOT NULL, - LastName VARCHAR(50) NOT NULL, - Email VARCHAR(100) NOT NULL UNIQUE CHECK (Email LIKE '%@%.%'), - Phone VARCHAR(15) NOT NULL UNIQUE CHECK (Phone LIKE '[0-9][0-9][0-9]-[0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]'), - JoinDate DATE DEFAULT GETDATE(), - Status VARCHAR(20) DEFAULT 'Active' CHECK (Status IN ('Active', 'Inactive', 'On Leave')), - Salary DECIMAL(10,2) CHECK (Salary >= 0), - Department VARCHAR(50) CHECK (Department IN ('IT', 'HR', 'Finance', 'Marketing', 'Sales')) -); -GO \ No newline at end of file diff --git a/test/JDBC/input/xml/openxml_with_clause-vu-verify.sql b/test/JDBC/input/xml/openxml_with_clause-vu-verify.sql index 9af54dc31d0..bf823fac1cb 100644 --- a/test/JDBC/input/xml/openxml_with_clause-vu-verify.sql +++ b/test/JDBC/input/xml/openxml_with_clause-vu-verify.sql @@ -782,53 +782,5 @@ OUTER APPLY WHERE s.region_id = r.region_id OR s.region_id IS NULL; EXEC sp_xml_removedocument @xml_doc3; +GO --- table having default constraints -DECLARE @DocHandle int; -DECLARE @XmlDocument nvarchar(max); - -SET @XmlDocument = N' - - - 1001 - John - Doe - john.doe@company.com - 123-456-7890 - 2024-01-15 - Active - 50000.00 - IT - - - 1002 - Jane - Smith - jane.smith@company.com - 234-567-8901 - 2024-01-16 - Active - 60000.00 - HR - - - 1003 - Mike - Johnson - mike.j@company.com - 345-678-9012 - 2024-01-17 - On Leave - 55000.00 - Finance - -'; - -EXEC sp_xml_preparedocument @DocHandle OUTPUT, @XmlDocument; - -SELECT * -FROM OPENXML(@DocHandle, '/Employees/Employee' , 2) -WITH Employee_Details; - -EXEC sp_xml_removedocument @DocHandle; -GO \ No newline at end of file From ec85e81e037500d9702ff25a26d2d28961ad950d Mon Sep 17 00:00:00 2001 From: Harsh Dubey Date: Wed, 25 Jun 2025 15:51:16 +0000 Subject: [PATCH 21/40] Retrigger workflows From 04226b44886c575263db4030a6420ab810556751 Mon Sep 17 00:00:00 2001 From: Harsh Dubey Date: Mon, 15 Sep 2025 18:50:20 +0000 Subject: [PATCH 22/40] Adding the changes of prepare and remove doc Signed-off-by: Harsh Dubey --- .../babelfishpg_tsql--5.2.0--5.3.0.sql | 30 ------- contrib/babelfishpg_tsql/src/pltsql.h | 2 +- contrib/babelfishpg_tsql/src/procedures.c | 81 ++++++++++--------- test/JDBC/upgrade/13_4/schedule | 1 - test/JDBC/upgrade/16_11/schedule | 1 + test/JDBC/upgrade/17_6/schedule | 1 + 6 files changed, 44 insertions(+), 72 deletions(-) diff --git a/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--5.2.0--5.3.0.sql b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--5.2.0--5.3.0.sql index 723a13b8f30..578ca178539 100644 --- a/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--5.2.0--5.3.0.sql +++ b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--5.2.0--5.3.0.sql @@ -1039,36 +1039,6 @@ COMMENT ON FUNCTION sys.babelfish_broken_view_function() IS 'Internal function u -- Please have this be one of the last statements executed in this upgrade script. DROP PROCEDURE sys.babelfish_drop_deprecated_object(varchar, varchar, varchar); -CREATE OR REPLACE PROCEDURE sys.sp_xml_preparedocument( - INOUT "@hdoc" INTEGER, - IN "@xmltext" sys.VARCHAR DEFAULT NULL, - IN "@xpath_namespaces" sys.VARCHAR DEFAULT NULL -) -AS 'babelfishpg_tsql', 'sp_xml_preparedocument' -LANGUAGE C; -GRANT EXECUTE ON PROCEDURE sys.sp_xml_preparedocument( - INOUT INTEGER, IN sys.varchar, IN sys.varchar -) TO PUBLIC; - -CREATE OR REPLACE PROCEDURE sys.sp_xml_removedocument( - IN "@hdoc" INTEGER -) -AS 'babelfishpg_tsql', 'sp_xml_removedocument' -LANGUAGE C; -GRANT EXECUTE ON PROCEDURE sys.sp_xml_removedocument( - IN INTEGER -) TO PUBLIC; - -CREATE OR REPLACE FUNCTION sys.tsql_openxml_get_xmldoc(int) -RETURNS xml -AS 'babelfishpg_tsql', 'tsql_openxml_get_xmldoc' -LANGUAGE C STRICT; - -CREATE OR REPLACE FUNCTION sys.tsql_openxml_get_colpattern(text,int) -RETURNS sys.nvarchar -AS 'babelfishpg_tsql', 'tsql_openxml_get_colpattern' -LANGUAGE C STRICT; - -- After upgrade, always run analyze for all babelfish catalogs. CALL sys.analyze_babelfish_catalogs(); -- Reset search_path to not affect any subsequent scripts diff --git a/contrib/babelfishpg_tsql/src/pltsql.h b/contrib/babelfishpg_tsql/src/pltsql.h index 145a23d6e53..53c18dee325 100644 --- a/contrib/babelfishpg_tsql/src/pltsql.h +++ b/contrib/babelfishpg_tsql/src/pltsql.h @@ -2380,4 +2380,4 @@ extern char *tsql_format_type_extended(Oid type_oid, int32 typemod, bits16 flags extern const char *shipped_objects_not_in_sys_db[NUM_DB_OBJECTS][2]; -#endif /* PLTSQL_H */ \ No newline at end of file +#endif /* PLTSQL_H */ diff --git a/contrib/babelfishpg_tsql/src/procedures.c b/contrib/babelfishpg_tsql/src/procedures.c index b3b73d7f7c1..3780cf7493e 100644 --- a/contrib/babelfishpg_tsql/src/procedures.c +++ b/contrib/babelfishpg_tsql/src/procedures.c @@ -4348,8 +4348,8 @@ get_next_xml_handle_counter() errmsg("Out of XML Handles"))); } - /* Check if the handle is in the active set */ - if (bms_is_member(current_xml_handle_counter, active_xml_handles_counter)) + /* Check if the handle is in the active set and table exists */ + if (xml_handle_temp_table_name != NULL && bms_is_member(current_xml_handle_counter, active_xml_handles_counter)) { /* Handle is in active set, check if it actually exists in the table */ int document_id = 2 * current_xml_handle_counter - 1; @@ -4360,33 +4360,29 @@ get_next_xml_handle_counter() bool entry_exists = false; EphemeralNamedRelation enr = NULL; - /* Only check the table if it exists using ENR lookup */ - if (xml_handle_temp_table_name != NULL) + enr = get_ENR(currentQueryEnv, xml_handle_temp_table_name, true); + if (enr) { - enr = get_ENR(currentQueryEnv, xml_handle_temp_table_name, true); - if (enr) - { - relation = relation_open(enr->md.reliddesc, AccessShareLock); + relation = relation_open(enr->md.reliddesc, AccessShareLock); + + /* Set up scan key to look for this document_id */ + ScanKeyInit(&skey[0], + 1, + BTEqualStrategyNumber, F_INT4EQ, + Int32GetDatum(document_id)); - /* Set up scan key to look for this document_id */ - ScanKeyInit(&skey[0], - 1, - BTEqualStrategyNumber, F_INT4EQ, - Int32GetDatum(document_id)); - - /* Scan the table for this document_id */ - scan = systable_beginscan(relation, InvalidOid, false, NULL, 1, skey); - tuple = systable_getnext(scan); - - /* If we find a tuple, the entry exists */ - if (HeapTupleIsValid(tuple)) - { - entry_exists = true; - } - - systable_endscan(scan); - relation_close(relation, AccessShareLock); + /* Scan the table for this document_id */ + scan = systable_beginscan(relation, InvalidOid, false, NULL, 1, skey); + tuple = systable_getnext(scan); + + /* If we find a tuple, the entry exists */ + if (HeapTupleIsValid(tuple)) + { + entry_exists = true; } + + systable_endscan(scan); + relation_close(relation, AccessShareLock); } /* If no entry exists in the table, we can use this handle */ if (!entry_exists) @@ -4397,7 +4393,7 @@ get_next_xml_handle_counter() } else { - /* Handle is not in active set, we can use it */ + /* Handle is not in active set or table doesn't exist, we can use it */ handle_valid = true; } } @@ -4450,14 +4446,12 @@ create_xml_handle_columns(void) * Returns: * A unique table name with the base name and an MD5 hash suffix */ -#define MD5_HASH_LEN 32 - static char * generate_unique_table_name(const char *base_name) { - char md5[MD5_HASH_LEN + 1]; - const char *errstr = NULL; - bool success; + char md5[MD5_HASH_LEN + 1]; + const char *errstr = NULL; + bool success; /* Generate a unique input string for the MD5 hash */ char *random_input = psprintf("%s%d", base_name, rand()); @@ -4683,7 +4677,7 @@ insert_xml_handle_entry(xmltype *xml_data, xmltype *ns_data, int xml_data_length * is reset, which would cause the handles to be lost and potentially reused. */ oldContext = MemoryContextSwitchTo(TopMemoryContext); - active_xml_handles_counter = bms_add_member(active_xml_handles_counter, current_xml_handle_counter); + active_xml_handles_counter = bms_add_member(active_xml_handles_counter, handle_counter); MemoryContextSwitchTo(oldContext); } PG_FINALLY(); @@ -4722,12 +4716,19 @@ delete_xml_handle_entry(int document_id) bool table_exists = false; EphemeralNamedRelation enr = NULL; - /* Check for negative document ID */ - if (document_id <= 0) + /* Check for negative & zero document ID */ + if (document_id < 0) { ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("Could not find prepared statement with handle %d", document_id))); + errmsg("Could not find prepared statement with handle %d.", document_id))); + } + + if (document_id == 0) + { + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("sp_xml_removedocument: The value supplied for parameter number 1 is invalid."))); } /* Calculate the handle counter */ @@ -4738,7 +4739,7 @@ delete_xml_handle_entry(int document_id) { ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("Could not find prepared statement with handle %d", document_id))); + errmsg("Could not find prepared statement with handle %d.", document_id))); } /* Check if the table exists using ENR lookup by name */ @@ -4757,7 +4758,7 @@ delete_xml_handle_entry(int document_id) /* Table doesn't exist, so the handle definitely doesn't exist */ ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("Could not find prepared statement with handle %d", document_id))); + errmsg("Could not find prepared statement with handle %d.", document_id))); } ScanKeyInit(&skey[0], @@ -4799,7 +4800,7 @@ delete_xml_handle_entry(int document_id) { ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("Could not find prepared statement with handle %d", document_id))); + errmsg("Could not find prepared statement with handle %d.", document_id))); } } @@ -4915,7 +4916,7 @@ sp_xml_removedocument(PG_FUNCTION_ARGS) { ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("Could not find prepared statement with handle NULL"))); + errmsg("sp_xml_removedocument: The value supplied for parameter number 1 is invalid."))); } /* Get the document handle */ diff --git a/test/JDBC/upgrade/13_4/schedule b/test/JDBC/upgrade/13_4/schedule index bdd7dbf7fc8..5c764e6c46a 100644 --- a/test/JDBC/upgrade/13_4/schedule +++ b/test/JDBC/upgrade/13_4/schedule @@ -263,7 +263,6 @@ test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument openxml_with_clause -openxml_with_clause fixeddecimal_modulo BABEL-NUMERIC_EXPR test_conv_float_to_varchar_char_before_17_4 diff --git a/test/JDBC/upgrade/16_11/schedule b/test/JDBC/upgrade/16_11/schedule index 06ac311b32c..3461fe7dfb5 100644 --- a/test/JDBC/upgrade/16_11/schedule +++ b/test/JDBC/upgrade/16_11/schedule @@ -605,6 +605,7 @@ BABEL-USER-GRANT test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument +openxml_with_clause fixeddecimal_modulo BABEL-NUMERIC_EXPR test_conv_float_to_varchar_char diff --git a/test/JDBC/upgrade/17_6/schedule b/test/JDBC/upgrade/17_6/schedule index c454dc9ca70..186e0a6d7ec 100644 --- a/test/JDBC/upgrade/17_6/schedule +++ b/test/JDBC/upgrade/17_6/schedule @@ -610,6 +610,7 @@ BABEL-USER-GRANT test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument +openxml_with_clause fixeddecimal_modulo BABEL-NUMERIC_EXPR test_conv_float_to_varchar_char From 0b692fedae4eb90eccfe82337aeb4976ff9def63 Mon Sep 17 00:00:00 2001 From: Harsh Dubey Date: Tue, 16 Sep 2025 05:49:34 +0000 Subject: [PATCH 23/40] Rerun workflows Signed-off-by: Harsh Dubey From 5a93636656abe29e34c78152eae0d77e8ed50ba9 Mon Sep 17 00:00:00 2001 From: Harsh Dubey Date: Tue, 16 Sep 2025 06:18:12 +0000 Subject: [PATCH 24/40] Added changes in latest upgrade script Signed-off-by: Harsh Dubey --- .../sql/upgrades/babelfishpg_tsql--5.3.0--5.4.0.sql | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--5.3.0--5.4.0.sql b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--5.3.0--5.4.0.sql index 1acac0bc07b..6e36d8e0dc7 100644 --- a/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--5.3.0--5.4.0.sql +++ b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--5.3.0--5.4.0.sql @@ -223,6 +223,16 @@ GRANT EXECUTE ON PROCEDURE sys.sp_xml_removedocument( IN INTEGER ) TO PUBLIC; +CREATE OR REPLACE FUNCTION sys.tsql_openxml_get_xmldoc(int) +RETURNS xml +AS 'babelfishpg_tsql', 'tsql_openxml_get_xmldoc' +LANGUAGE C STRICT; + +CREATE OR REPLACE FUNCTION sys.tsql_openxml_get_colpattern(text,int) +RETURNS sys.nvarchar +AS 'babelfishpg_tsql', 'tsql_openxml_get_colpattern' +LANGUAGE C STRICT; + -- Drops the temporary procedure used by the upgrade script. -- Please have this be one of the last statements executed in this upgrade script. DROP PROCEDURE sys.babelfish_drop_deprecated_object(varchar, varchar, varchar); From ff9941387ab3e020a933a0d1bb22888604ccb19a Mon Sep 17 00:00:00 2001 From: Harsh Dubey Date: Tue, 16 Sep 2025 16:18:39 +0000 Subject: [PATCH 25/40] Refactor code Signed-off-by: Harsh Dubey --- contrib/babelfishpg_tsql/src/hooks.c | 13 ++++++++---- contrib/babelfishpg_tsql/src/procedures.c | 21 ++++++++++++------- .../openxml_with_clause-vu-verify.out | 4 +--- 3 files changed, 24 insertions(+), 14 deletions(-) diff --git a/contrib/babelfishpg_tsql/src/hooks.c b/contrib/babelfishpg_tsql/src/hooks.c index fea5966848c..4173578ce2d 100644 --- a/contrib/babelfishpg_tsql/src/hooks.c +++ b/contrib/babelfishpg_tsql/src/hooks.c @@ -6822,8 +6822,9 @@ pre_transform_openxml_columns(ParseState *pstate, RangeTableFunc *rtf) rtf->namespaces = NIL; /* - * Set the document expression to retrieve the XML document using the document handle. This creates a function call to tsql_openxml_get_xmldoc - * which retrieves the previously prepared XML document based on the document ID from sp_xml_preparedocument. + * Set the document expression to retrieve the XML document using the document handle. + * This creates a function call to tsql_openxml_get_xmldoc which retrieves the previously + * prepared XML document based on the document ID from sp_xml_preparedocument. */ rtf->docexpr = (Node *) makeFuncCall(list_make2(makeString("sys"), makeString("tsql_openxml_get_xmldoc")), list_make1(tsql_docid_node), COERCE_EXPLICIT_CALL, -1); @@ -6849,14 +6850,18 @@ pre_transform_openxml_columns(ParseState *pstate, RangeTableFunc *rtf) /* If no column expression is provided, generate one based on the flag */ if(fc->colexpr == NULL && tsql_flag != NULL) { - /* To get original column name, utilize location of ColumnDef and query string. For colexpr, we need orignal name of columns (no downcase or uppercase) */ + /* + * To get original column name, utilize location of ColumnDef and query string. + * For colexpr, we need orignal name of columns (no downcase or uppercase) + */ const char *column_name_start = pstate->p_sourcetext + fc->location; char *original_name = extract_identifier(column_name_start, NULL); if (original_name == NULL) original_name = fc->colname; /* - * Create an XPath expression for the column using tsql_openxml_get_colpattern. This builds a function call to generate the appropriate XPath pattern + * Create an XPath expression for the column using tsql_openxml_get_colpattern. + * This builds a function call to generate the appropriate XPath pattern * based on the column name and the OPENXML flag parameter */ fc->colexpr = (Node *) makeFuncCall(list_make2(makeString("sys"), makeString("tsql_openxml_get_colpattern")), list_make2(makeStringConst(original_name, -1), tsql_flag), COERCE_EXPLICIT_CALL, -1); diff --git a/contrib/babelfishpg_tsql/src/procedures.c b/contrib/babelfishpg_tsql/src/procedures.c index 3780cf7493e..b31eb145722 100644 --- a/contrib/babelfishpg_tsql/src/procedures.c +++ b/contrib/babelfishpg_tsql/src/procedures.c @@ -118,6 +118,8 @@ char *orig_proc_funcname = NULL; static bool is_supported_case_sp_describe_undeclared_parameters = true; #define MD5_HASH_LEN 32 +#define Anum_xml_handle_temp_table_xml_data 6 +#define Anum_xml_handle_temp_table_doc_id 1 const int XML_HANDLE_COUNTER_START = 0; const int XML_HANDLE_COUNTER_INVALID = INT_MAX / 2; static int current_xml_handle_counter = INT_MAX / 2; @@ -4931,7 +4933,6 @@ sp_xml_removedocument(PG_FUNCTION_ARGS) /* * Function to retrieve XML document from temporary table using document ID */ -#define XML_HANDLE_DOC_COLUMN_NUM 6 Datum tsql_openxml_get_xmldoc(PG_FUNCTION_ARGS) { @@ -4961,11 +4962,11 @@ tsql_openxml_get_xmldoc(PG_FUNCTION_ARGS) { ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("Could not find prepared statement with handle %d", document_id))); + errmsg("Could not find prepared statement with handle %d.", document_id))); } ScanKeyInit(&skey[0], - 1, /* Column number */ + Anum_xml_handle_temp_table_doc_id, /* Column number */ BTEqualStrategyNumber, F_INT4EQ, Int32GetDatum(document_id)); @@ -4975,7 +4976,7 @@ tsql_openxml_get_xmldoc(PG_FUNCTION_ARGS) if (HeapTupleIsValid(tuple)) { /* Get the XML document from column 6 (doc) */ - result = heap_getattr(tuple, XML_HANDLE_DOC_COLUMN_NUM, RelationGetDescr(relation), &isnull); + result = heap_getattr(tuple, Anum_xml_handle_temp_table_xml_data, RelationGetDescr(relation), &isnull); if (!isnull) { @@ -4983,6 +4984,14 @@ tsql_openxml_get_xmldoc(PG_FUNCTION_ARGS) result = datumCopy(result, false, -1); found = true; } + + else + { + /* Document is NULL, return NULL */ + table_endscan(scan); + relation_close(relation, AccessShareLock); + PG_RETURN_NULL(); + } } table_endscan(scan); @@ -4995,9 +5004,7 @@ tsql_openxml_get_xmldoc(PG_FUNCTION_ARGS) /* If we didn't find the handle , throw an error */ ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("Could not find prepared statement with handle %d", document_id))); - - PG_RETURN_NULL(); + errmsg("Could not find prepared statement with handle %d.", document_id))); } /* diff --git a/test/JDBC/expected/openxml_with_clause-vu-verify.out b/test/JDBC/expected/openxml_with_clause-vu-verify.out index c9a79bcbb8d..77933dfca8d 100644 --- a/test/JDBC/expected/openxml_with_clause-vu-verify.out +++ b/test/JDBC/expected/openxml_with_clause-vu-verify.out @@ -754,9 +754,7 @@ EXEC sp_xml_removedocument @DocHandle; GO ~~START~~ varchar#!#varchar -~~ERROR (Code: 33557097)~~ - -~~ERROR (Message: Could not find prepared statement with handle 43)~~ +~~END~~ From dbd2fde66b3f757b31eae14fa9088e2be4454d8d Mon Sep 17 00:00:00 2001 From: Harsh Dubey Date: Tue, 16 Sep 2025 18:54:52 +0000 Subject: [PATCH 26/40] Assigned doc_id to rtf->docexpr node Signed-off-by: Harsh Dubey --- .../src/backend_parser/gram-tsql-rule.y | 18 +++++++++--------- contrib/babelfishpg_tsql/src/hooks.c | 5 +++-- .../expected/openxml_with_clause-vu-verify.out | 2 +- .../xml/openxml_with_clause-vu-verify.sql | 2 +- 4 files changed, 14 insertions(+), 13 deletions(-) diff --git a/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-rule.y b/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-rule.y index 929990a0faf..105c7cb6346 100644 --- a/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-rule.y +++ b/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-rule.y @@ -1803,11 +1803,11 @@ table_ref: relation_expr tsql_table_hint_expr openxml_expr: OPENXML '(' a_expr ',' a_expr ')' WITH_table TABLE qualified_name opt_alias_clause { RangeTableFunc *n = makeNode(RangeTableFunc); - n->docexpr = NULL; + n->docexpr = $3; n->rowexpr = $5; n->location = @1; /* Default flag is 0 when not specified */ - n->namespaces = list_make2((Node *)$3, makeIntConst(0, @1)); + n->namespaces = list_make1(makeIntConst(0, @1)); n->columns = list_make1($9); n->alias = $10; $$ = (Node *) n; @@ -1815,10 +1815,10 @@ openxml_expr: OPENXML '(' a_expr ',' a_expr ')' WITH_table TABLE qualified_name | OPENXML '(' a_expr ',' a_expr ',' a_expr ')' WITH_table TABLE qualified_name opt_alias_clause { RangeTableFunc *n = makeNode(RangeTableFunc); - n->docexpr = NULL; + n->docexpr = $3; n->rowexpr = $5; n->location = @1; - n->namespaces = list_make2((Node *)$3, (Node *)$7); + n->namespaces = list_make1((Node *)$7); n->columns = list_make1($11); n->alias = $12; $$ = (Node *) n; @@ -1826,23 +1826,23 @@ openxml_expr: OPENXML '(' a_expr ',' a_expr ')' WITH_table TABLE qualified_name | OPENXML '(' a_expr ',' a_expr ')' WITH_paren '(' openxml_column_list ')' opt_alias_clause { RangeTableFunc *n = makeNode(RangeTableFunc); - n->docexpr = NULL; + n->docexpr = $3; n->rowexpr = $5; n->location = @1; - /* Default flag is 0 when not specified */ n->columns = $9; - n->namespaces = list_make2((Node *)$3, makeIntConst(0, @1)); + /* Default flag is 0 when not specified */ + n->namespaces = list_make1(makeIntConst(0, @1)); n->alias = $11; $$ = (Node *) n; } | OPENXML '(' a_expr ',' a_expr ',' a_expr ')' WITH_paren '(' openxml_column_list ')' opt_alias_clause { RangeTableFunc *n = makeNode(RangeTableFunc); - n->docexpr = NULL; + n->docexpr = $3; n->rowexpr = $5; n->columns = $11; n->location = @1; - n->namespaces = list_make2((Node *)$3, (Node *)$7); + n->namespaces = list_make1((Node *)$7); n->alias = $13; $$ = (Node *) n; } diff --git a/contrib/babelfishpg_tsql/src/hooks.c b/contrib/babelfishpg_tsql/src/hooks.c index 4173578ce2d..55a3a3e5a98 100644 --- a/contrib/babelfishpg_tsql/src/hooks.c +++ b/contrib/babelfishpg_tsql/src/hooks.c @@ -6816,10 +6816,11 @@ pre_transform_openxml_columns(ParseState *pstate, RangeTableFunc *rtf) if (sql_dialect != SQL_DIALECT_TSQL) return; - tsql_docid_node = linitial(rtf->namespaces); - tsql_flag = lsecond(rtf->namespaces); + tsql_docid_node = rtf->docexpr; + tsql_flag = linitial(rtf->namespaces); rtf->namespaces = NIL; + rtf->docexpr = NULL; /* * Set the document expression to retrieve the XML document using the document handle. diff --git a/test/JDBC/expected/openxml_with_clause-vu-verify.out b/test/JDBC/expected/openxml_with_clause-vu-verify.out index 77933dfca8d..ec7d3c4ee80 100644 --- a/test/JDBC/expected/openxml_with_clause-vu-verify.out +++ b/test/JDBC/expected/openxml_with_clause-vu-verify.out @@ -743,7 +743,7 @@ Bob Wilson#!##!##!##!# -- Test with empty XML document DECLARE @DocHandle int; -EXEC sp_xml_preparedocument @DocHandle OUTPUT, @DocHandle; +EXEC sp_xml_preparedocument @DocHandle OUTPUT; SELECT * FROM OPENXML (@DocHandle, '/', 1) WITH ( diff --git a/test/JDBC/input/xml/openxml_with_clause-vu-verify.sql b/test/JDBC/input/xml/openxml_with_clause-vu-verify.sql index bf823fac1cb..25e28affcd2 100644 --- a/test/JDBC/input/xml/openxml_with_clause-vu-verify.sql +++ b/test/JDBC/input/xml/openxml_with_clause-vu-verify.sql @@ -596,7 +596,7 @@ GO -- Test with empty XML document DECLARE @DocHandle int; -EXEC sp_xml_preparedocument @DocHandle OUTPUT, @DocHandle; +EXEC sp_xml_preparedocument @DocHandle OUTPUT; SELECT * FROM OPENXML (@DocHandle, '/', 1) WITH ( From e35b18768fa9a5878278a310901987d4337a9993 Mon Sep 17 00:00:00 2001 From: Harsh Dubey Date: Wed, 17 Sep 2025 05:38:02 +0000 Subject: [PATCH 27/40] Updated the schedule files Signed-off-by: Harsh Dubey --- contrib/babelfishpg_tsql/sql/sys_functions.sql | 2 ++ test/JDBC/upgrade/15_12/schedule | 1 + test/JDBC/upgrade/15_14/schedule | 1 + test/JDBC/upgrade/15_15/schedule | 1 + test/JDBC/upgrade/16_10/schedule | 1 + test/JDBC/upgrade/16_8/schedule | 1 + test/JDBC/upgrade/17_4/schedule | 1 + test/JDBC/upgrade/17_5/schedule | 1 + 8 files changed, 9 insertions(+) diff --git a/contrib/babelfishpg_tsql/sql/sys_functions.sql b/contrib/babelfishpg_tsql/sql/sys_functions.sql index fc1ea75ff1d..123f6b79e2a 100644 --- a/contrib/babelfishpg_tsql/sql/sys_functions.sql +++ b/contrib/babelfishpg_tsql/sql/sys_functions.sql @@ -4108,11 +4108,13 @@ CREATE OR REPLACE FUNCTION sys.openjson_with(json_string text, path text, VARIAD RETURNS SETOF RECORD AS 'babelfishpg_tsql', 'tsql_openjson_with' LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE; +/* Function to retrieve XML doc from temp table using doc_id (for openxml) */ CREATE OR REPLACE FUNCTION sys.tsql_openxml_get_xmldoc(int) RETURNS xml AS 'babelfishpg_tsql', 'tsql_openxml_get_xmldoc' LANGUAGE C STRICT; +/* This function generates XPath expressions for OPENXML columns */ CREATE OR REPLACE FUNCTION sys.tsql_openxml_get_colpattern(text,int) RETURNS sys.nvarchar AS 'babelfishpg_tsql', 'tsql_openxml_get_colpattern' diff --git a/test/JDBC/upgrade/15_12/schedule b/test/JDBC/upgrade/15_12/schedule index 3b74bf4be17..64b7da93a43 100644 --- a/test/JDBC/upgrade/15_12/schedule +++ b/test/JDBC/upgrade/15_12/schedule @@ -570,6 +570,7 @@ BABEL-USER-GRANT test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument +openxml_with_clause fixeddecimal_modulo BABEL-NUMERIC_EXPR BABEL-5467 diff --git a/test/JDBC/upgrade/15_14/schedule b/test/JDBC/upgrade/15_14/schedule index 78526d24c4d..762d2f9b019 100644 --- a/test/JDBC/upgrade/15_14/schedule +++ b/test/JDBC/upgrade/15_14/schedule @@ -570,6 +570,7 @@ BABEL-USER-GRANT test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument +openxml_with_clause fixeddecimal_modulo BABEL-NUMERIC_EXPR BABEL-5467 diff --git a/test/JDBC/upgrade/15_15/schedule b/test/JDBC/upgrade/15_15/schedule index 89cda417716..9c1aef725f8 100644 --- a/test/JDBC/upgrade/15_15/schedule +++ b/test/JDBC/upgrade/15_15/schedule @@ -568,6 +568,7 @@ test_conv_string_to_time-before-17_4 BABEL-5031 BABEL-USER-GRANT test_conv_money_to_varchar +openxml_with_clause fixeddecimal_modulo BABEL-NUMERIC_EXPR BABEL-5467 diff --git a/test/JDBC/upgrade/16_10/schedule b/test/JDBC/upgrade/16_10/schedule index 3ceec9605ae..3829427d241 100644 --- a/test/JDBC/upgrade/16_10/schedule +++ b/test/JDBC/upgrade/16_10/schedule @@ -605,6 +605,7 @@ BABEL-USER-GRANT test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument +openxml_with_clause fixeddecimal_modulo BABEL-NUMERIC_EXPR test_conv_float_to_varchar_char diff --git a/test/JDBC/upgrade/16_8/schedule b/test/JDBC/upgrade/16_8/schedule index 14c25309a24..ababce5b8c6 100644 --- a/test/JDBC/upgrade/16_8/schedule +++ b/test/JDBC/upgrade/16_8/schedule @@ -604,6 +604,7 @@ BABEL-USER-GRANT test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument +openxml_with_clause fixeddecimal_modulo BABEL-NUMERIC_EXPR test_conv_float_to_varchar_char diff --git a/test/JDBC/upgrade/17_4/schedule b/test/JDBC/upgrade/17_4/schedule index 1f748218b3f..13f7797c4d7 100644 --- a/test/JDBC/upgrade/17_4/schedule +++ b/test/JDBC/upgrade/17_4/schedule @@ -601,6 +601,7 @@ BABEL-USER-GRANT test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument +openxml_with_clause fixeddecimal_modulo BABEL-NUMERIC_EXPR test_conv_float_to_varchar_char diff --git a/test/JDBC/upgrade/17_5/schedule b/test/JDBC/upgrade/17_5/schedule index f20dc62a4a0..f578b63d6c4 100644 --- a/test/JDBC/upgrade/17_5/schedule +++ b/test/JDBC/upgrade/17_5/schedule @@ -606,6 +606,7 @@ BABEL-USER-GRANT test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument +openxml_with_clause fixeddecimal_modulo BABEL-NUMERIC_EXPR test_conv_float_to_varchar_char From ad68fa3b1062614bac1d96facd6f7cf2f5922a03 Mon Sep 17 00:00:00 2001 From: Harsh Dubey Date: Wed, 17 Sep 2025 13:06:14 +0000 Subject: [PATCH 28/40] Adding namespaces support in openxml with clause Signed-off-by: Harsh Dubey --- contrib/babelfishpg_tsql/runtime/functions.c | 110 ++++ contrib/babelfishpg_tsql/src/hooks.c | 76 +++ contrib/babelfishpg_tsql/src/pltsql.h | 5 + contrib/babelfishpg_tsql/src/procedures.c | 117 ++-- .../openxml_with_clause-vu-verify.out | 523 ++++++++++++++++++ .../xml/openxml_with_clause-vu-verify.sql | 437 +++++++++++++++ 6 files changed, 1229 insertions(+), 39 deletions(-) diff --git a/contrib/babelfishpg_tsql/runtime/functions.c b/contrib/babelfishpg_tsql/runtime/functions.c index ba4b193efa6..8d9a3209700 100644 --- a/contrib/babelfishpg_tsql/runtime/functions.c +++ b/contrib/babelfishpg_tsql/runtime/functions.c @@ -49,6 +49,7 @@ #include "utils/queryenvironment.h" #include "utils/float.h" #include "utils/xid8.h" +#include "utils/xml.h" #include #include "../src/babelfish_version.h" @@ -72,6 +73,12 @@ #include "catalog/pg_constraint.h" #include "parser/parse_oper.h" +#ifdef USE_LIBXML +#include +#include +#include +#endif /* USE_LIBXML */ + #define TSQL_STAT_GET_ACTIVITY_COLS 26 #define SP_DATATYPE_INFO_HELPER_COLS 23 #define SYSVARCHAR_MAX_LENGTH 4000 @@ -203,6 +210,9 @@ void *get_servername_internal(void); void *get_servicename_internal(void); void *get_language(void); void *get_host_id(void); +#ifdef USE_LIBXML +void extract_namespaces_from_xml(xmltype *ns_data, char ***ns_names, char ***ns_uris, int *ns_count); +#endif Datum datepart_internal(char *field , Timestamp timestamp , float8 df_tz, bool general_integer_datatype); static HTAB *load_categories_hash(const char *sourcetext, MemoryContext per_query_ctx); @@ -235,6 +245,29 @@ extern bool inited_ht_tsql_datatype_precedence_info; extern PLtsql_execstate *get_outermost_tsql_estate(int *nestlevel); extern char *replace_special_chars_fts_impl(char *input_str); +#ifdef USE_LIBXML +struct PgXmlErrorContext +{ + int magic; + /* strictness argument passed to pg_xml_init */ + PgXmlStrictness strictness; + /* current error status and accumulated message, if any */ + bool err_occurred; + StringInfoData err_buf; + /* previous libxml error handling state (saved by pg_xml_init) */ + xmlStructuredErrorFunc saved_errfunc; + void *saved_errcxt; + /* previous libxml entity handler (saved by pg_xml_init) */ + xmlExternalEntityLoader saved_entityfunc; +}; +#endif /* USE_LIBXML */ + +#define NO_XML_SUPPORT() \ + ereport(ERROR, \ + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), \ + errmsg("unsupported XML feature"), \ + errdetail("This functionality requires the server to be built with libxml support."))) + char *bbf_servername = "BABELFISH"; const char *bbf_servicename = "MSSQLSERVER"; char *bbf_language = "us_english"; @@ -5123,3 +5156,80 @@ get_bbf_pivot_tuplestore(const char *sourcetext, return tupstore; } + +#ifdef USE_LIBXML +/* + * extract_namespaces_from_xml + * Extracts namespace names and URIs from root node of the given XML data. + * + * Note: The extracted names and URIs are stored in ns_names and ns_uris respectively. + * The count of extracted namespaces is stored in ns_count. If no namespaces are found, + * ns_names and ns_uris are set to NULL and ns_count to 0. + */ +void +extract_namespaces_from_xml(xmltype *ns_data, char ***ns_names, char ***ns_uris, int *ns_count) +{ + xmlDocPtr doc; + xmlNode *root; + int index; + + /* Unlikely, just a sanity check */ + if (ns_names == NULL || ns_uris == NULL || ns_count == NULL) + return; + + *ns_names = NULL; + *ns_uris = NULL; + *ns_count = 0; + + if (ns_data == NULL) + return; + + doc = xml_parse_wrapper(ns_data, XMLOPTION_DOCUMENT, false, GetDatabaseEncoding(), NULL, NULL, NULL); + + if (doc == NULL) + return; + + /* + * Get namespace declaration count + */ + root = xmlDocGetRootElement(doc); + for (xmlNs *cur = root->nsDef; cur != NULL; cur = cur->next) + { + /* Ignore default namespace declaration */ + if (cur->prefix) + { + (*ns_count)++; + } + } + + if (*ns_count == 0) + { + if (doc) + xmlFreeDoc(doc); + return; + } + + /* + * Allocate memory for namespace names and URIs + */ + *ns_names = (char **) palloc0((*ns_count) * sizeof(char *)); + *ns_uris = (char **) palloc0((*ns_count) * sizeof(char *)); + + /* + * Store namespace names and URIs in ns_names and ns_uris + */ + index = 0; + for (xmlNs *cur = root->nsDef; cur != NULL; cur = cur->next) + { + if (cur->prefix) + { + (*ns_names)[index] = (char *) pstrdup((const char *) cur->prefix); + (*ns_uris)[index] = cur->href ? (char *) pstrdup((const char *) cur->href) : NULL; + index++; + } + } + + if (doc) + xmlFreeDoc(doc); +} +#endif \ No newline at end of file diff --git a/contrib/babelfishpg_tsql/src/hooks.c b/contrib/babelfishpg_tsql/src/hooks.c index 55a3a3e5a98..0a15c38449f 100644 --- a/contrib/babelfishpg_tsql/src/hooks.c +++ b/contrib/babelfishpg_tsql/src/hooks.c @@ -95,6 +95,13 @@ #include "table_variable_mvcc.h" #include "bbf_parallel_query.h" #include "extendedproperty.h" +#include "utils/xml.h" + +#ifdef USE_LIBXML +#include +#include +#include +#endif /* USE_LIBXML */ #define TDS_NUMERIC_MAX_PRECISION 38 @@ -260,6 +267,9 @@ static const char *remove_db_name_in_schema(const char *schema_name, const char static int32 pltsql_exprTypmod(Plan *plan, Node *expr); static Oid get_domain_typmodin(Type typ); static void pre_transform_openxml_columns(ParseState *pstate, RangeTableFunc *rtf); +#ifdef USE_LIBXML +static void openxml_set_namespaces(xmlXPathContext *xpathctx, PgXmlErrorContext *xmlerrcxt, char *doc_id_str); +#endif /*************************************************** * Temp Table Related Declarations + Hooks @@ -362,6 +372,9 @@ static validateCachedPlanSearchPath_hook_type prev_validateCachedPlanSearchPath_ static pre_QueryRewrite_hook_type prev_pre_QueryRewrite_hook = NULL; ExecInitParallelPlan_hook_type prev_ExecInitParallelPlan_hook = NULL; ParallelQueryMain_hook_type prev_ParallelQueryMain_hook = NULL; +#ifdef USE_LIBXML +static openxml_set_namespaces_hook_type prev_openxml_set_namespaces_hook = NULL; +#endif /***************************************** * Install / Uninstall @@ -494,6 +507,11 @@ InstallExtendedHooks(void) prev_pre_transform_openxml_columns_hook = pre_transform_openxml_columns_hook; pre_transform_openxml_columns_hook = pre_transform_openxml_columns; + #ifdef USE_LIBXML + prev_openxml_set_namespaces_hook = openxml_set_namespaces_hook; + openxml_set_namespaces_hook = openxml_set_namespaces; + #endif + prev_print_pltsql_function_arguments_hook = print_pltsql_function_arguments_hook; print_pltsql_function_arguments_hook = print_pltsql_function_arguments; @@ -701,6 +719,9 @@ UninstallExtendedHooks(void) bbf_check_member_has_direct_priv_to_grant_role_hook = prev_bbf_check_member_has_direct_priv_to_grant_role_hook; validateCachedPlanSearchPath_hook = prev_validateCachedPlanSearchPath_hook; pre_QueryRewrite_hook = prev_pre_QueryRewrite_hook; + #ifdef USE_LIBXML + openxml_set_namespaces_hook = prev_openxml_set_namespaces_hook; + #endif bbf_InitializeParallelDSM_hook = NULL; bbf_ParallelWorkerMain_hook = NULL; @@ -6812,6 +6833,7 @@ pre_transform_openxml_columns(ParseState *pstate, RangeTableFunc *rtf) Node *tsql_docid_node; Node *tsql_flag; RangeVar *table_ref; + ResTarget *res = makeNode(ResTarget); if (sql_dialect != SQL_DIALECT_TSQL) return; @@ -6822,6 +6844,14 @@ pre_transform_openxml_columns(ParseState *pstate, RangeTableFunc *rtf) rtf->namespaces = NIL; rtf->docexpr = NULL; + /* Storing doc_id in the res->name field */ + res->name = pstrdup("openxml_doc_id"); + res->name_location = -1; + res->indirection = NIL; + res->val = tsql_docid_node; + res->location = -1; + rtf->namespaces = list_make1(res); + /* * Set the document expression to retrieve the XML document using the document handle. * This creates a function call to tsql_openxml_get_xmldoc which retrieves the previously @@ -6872,6 +6902,52 @@ pre_transform_openxml_columns(ParseState *pstate, RangeTableFunc *rtf) } } +#ifdef USE_LIBXML +static void +openxml_set_namespaces(xmlXPathContext *xpathctx, PgXmlErrorContext *xmlerrcxt, char *doc_id_str) +{ + int doc_id; + xmltype *ns_data; + char **ns_names; + char **ns_uris; + int ns_count; + + if (sql_dialect != SQL_DIALECT_TSQL) + return; + + doc_id = pg_strtoint32(doc_id_str); + get_xml_data_and_namespace_data(doc_id, NULL, &ns_data); + if (ns_data == NULL) + return; + + extract_namespaces_from_xml(ns_data, &ns_names, &ns_uris, &ns_count); + + /* register namespaces, if any */ + if (ns_count > 0) + { + for (int i = 0; i < ns_count; i++) + { + char *ns_name; + char *ns_uri; + + if (ns_names[i] == NULL || ns_uris[i] == NULL) + ereport(ERROR, + (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), + errmsg("neither namespace name nor URI may be null"))); + + ns_name = ns_names[i]; + ns_uri = ns_uris[i]; + + if (xmlXPathRegisterNs(xpathctx, + pg_xmlCharStrndup_wrapper(ns_name, strlen(ns_name)), + pg_xmlCharStrndup_wrapper(ns_uri, strlen(ns_uri))) != 0) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_DATA_EXCEPTION, + "could not set XML namespace"); + } + } +} +#endif + /* * pltsql_ExecUpdateResultTypeTL * diff --git a/contrib/babelfishpg_tsql/src/pltsql.h b/contrib/babelfishpg_tsql/src/pltsql.h index 53c18dee325..3e3396da9a0 100644 --- a/contrib/babelfishpg_tsql/src/pltsql.h +++ b/contrib/babelfishpg_tsql/src/pltsql.h @@ -33,6 +33,7 @@ #include "utils/portal.h" #include "utils/typcache.h" #include "tcop/utility.h" +#include "utils/xml.h" #include "dynavec.h" #include "dynastack.h" @@ -2179,6 +2180,10 @@ extern int pltsql_yyparse(void); /* functions in hooks.c */ extern char *extract_identifier(const char *start, int *last_pos); +extern void get_xml_data_and_namespace_data(int document_id, xmltype **xml_data, xmltype **ns_data); +#ifdef USE_LIBXML +extern void extract_namespaces_from_xml(xmltype *ns_data, char ***ns_names, char ***ns_uris, int *ns_count); +#endif /* functions in pltsql_utils.c */ extern char *gen_createfulltextindex_cmds(const char *table_name, const char *schema_name, const List *column_name, const char *index_name); diff --git a/contrib/babelfishpg_tsql/src/procedures.c b/contrib/babelfishpg_tsql/src/procedures.c index b31eb145722..ec5cfcbb68e 100644 --- a/contrib/babelfishpg_tsql/src/procedures.c +++ b/contrib/babelfishpg_tsql/src/procedures.c @@ -117,9 +117,11 @@ bool sp_describe_first_result_set_inprogress = false; char *orig_proc_funcname = NULL; static bool is_supported_case_sp_describe_undeclared_parameters = true; -#define MD5_HASH_LEN 32 +#define Anum_xml_handle_temp_table_document_id 1 #define Anum_xml_handle_temp_table_xml_data 6 -#define Anum_xml_handle_temp_table_doc_id 1 +#define Anum_xml_handle_temp_table_ns_data 7 + +#define MD5_HASH_LEN 32 const int XML_HANDLE_COUNTER_START = 0; const int XML_HANDLE_COUNTER_INVALID = INT_MAX / 2; static int current_xml_handle_counter = INT_MAX / 2; @@ -129,6 +131,7 @@ int get_next_xml_handle_counter(void); void create_xml_handle_temp_table(void); void delete_xml_handle_entry(int handle); int insert_xml_handle_entry(xmltype *xml_data,xmltype *ns_data, int xml_data_length, int ns_data_length); +void get_xml_data_and_namespace_data(int document_id, xmltype **xml_data, xmltype **ns_data); /* server options and their default values for babelfish_server_options catalog insert */ char * srvOptions_optname[BBF_SERVERS_DEF_NUM_COLS - 1] = {"query timeout", "connect timeout"}; @@ -4931,23 +4934,35 @@ sp_xml_removedocument(PG_FUNCTION_ARGS) } /* - * Function to retrieve XML document from temporary table using document ID + * Function to retrieve XML document and namespace from temporary table using document ID */ -Datum -tsql_openxml_get_xmldoc(PG_FUNCTION_ARGS) +void +get_xml_data_and_namespace_data(int document_id, xmltype **xml_data, xmltype **ns_data) { - int32 document_id = PG_GETARG_INT32(0); - Relation relation; - ScanKeyData skey[1]; - TableScanDesc scan; - HeapTuple tuple; - bool found = false; - Datum result = (Datum) 0; - bool isnull = true; - EphemeralNamedRelation enr = NULL; - bool table_exists = false; - - /* Check if the temporary table exists */ + EphemeralNamedRelation enr = NULL; + Relation relation; + ScanKeyData skey[1]; + TableScanDesc scan; + HeapTuple tuple; + Datum datum; + bool isnull; + bool table_exists = false; + + if (xml_data == NULL && ns_data == NULL) + return; + + /* + * Initialise xml_data and ns_data to NULL. + */ + if (xml_data) + *xml_data = NULL; + if (ns_data) + *ns_data = NULL; + + /* + * Check if the xml_handle_temp_table exists using ENR lookup, + * if found get its relation descriptor. + */ if (xml_handle_temp_table_name != NULL) { enr = get_ENR(currentQueryEnv, xml_handle_temp_table_name, true); @@ -4965,46 +4980,70 @@ tsql_openxml_get_xmldoc(PG_FUNCTION_ARGS) errmsg("Could not find prepared statement with handle %d.", document_id))); } + /* + * Fetch xml data and namespace data from xml_handle_temp_table, for given document id. + */ ScanKeyInit(&skey[0], - Anum_xml_handle_temp_table_doc_id, /* Column number */ + Anum_xml_handle_temp_table_document_id, BTEqualStrategyNumber, F_INT4EQ, Int32GetDatum(document_id)); - + scan = table_beginscan_catalog(relation, 1, skey); tuple = heap_getnext(scan, ForwardScanDirection); - + if (HeapTupleIsValid(tuple)) { - /* Get the XML document from column 6 (doc) */ - result = heap_getattr(tuple, Anum_xml_handle_temp_table_xml_data, RelationGetDescr(relation), &isnull); - - if (!isnull) + /* Get the XML document */ + if (xml_data) { - /* Make a copy of the value */ - result = datumCopy(result, false, -1); - found = true; + isnull = true; + datum = heap_getattr(tuple, Anum_xml_handle_temp_table_xml_data, RelationGetDescr(relation), &isnull); + + if (!isnull) + *xml_data = DatumGetXmlP(datum); + else + *xml_data = NULL; } - else + /* Get the namespaces */ + if (ns_data) { - /* Document is NULL, return NULL */ - table_endscan(scan); - relation_close(relation, AccessShareLock); - PG_RETURN_NULL(); + isnull = true; + datum = heap_getattr(tuple, Anum_xml_handle_temp_table_ns_data, RelationGetDescr(relation), &isnull); + + if (!isnull) + *ns_data = DatumGetXmlP(datum); + else + *ns_data = NULL; } } - + else + { + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("Could not find prepared statement with handle %d.", document_id))); + } + table_endscan(scan); relation_close(relation, AccessShareLock); +} + +/* + * Function to retrieve XML document using document ID + */ +Datum +tsql_openxml_get_xmldoc(PG_FUNCTION_ARGS) +{ + int32 document_id = PG_GETARG_INT32(0); + xmltype *xmldata = NULL; + + get_xml_data_and_namespace_data(document_id, &xmldata, NULL); /* If we found the document, return it */ - if (found) - PG_RETURN_DATUM(result); + if (xmldata) + PG_RETURN_XML_P(xmldata); - /* If we didn't find the handle , throw an error */ - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("Could not find prepared statement with handle %d.", document_id))); + PG_RETURN_NULL(); } /* diff --git a/test/JDBC/expected/openxml_with_clause-vu-verify.out b/test/JDBC/expected/openxml_with_clause-vu-verify.out index ec7d3c4ee80..86f26b4b80f 100644 --- a/test/JDBC/expected/openxml_with_clause-vu-verify.out +++ b/test/JDBC/expected/openxml_with_clause-vu-verify.out @@ -981,3 +981,526 @@ int#!#varchar#!#numeric#!#varchar ~~END~~ +-- With namespaces +--test1 +DECLARE @xml nvarchar(1000) = +' + value1 + value2 +'; +DECLARE @namespace nvarchar(100) = ''; +DECLARE @handle INT; +EXEC sp_xml_preparedocument @handle OUTPUT, @xml, @namespace; +SELECT * FROM OPENXML(@handle, '/root/ns1:child', 3) WITH (child nvarchar(10) '.'); +EXEC sp_xml_removedocument @handle; +GO +~~START~~ +nvarchar +value1 +~~END~~ + + + +DECLARE @h int; +EXEC sp_xml_preparedocument @h OUTPUT, + N' + + TaU + + ', + ''; +SELECT * FROM openxml(@h, '/root/b:Elem', 3) + WITH (Col1 varchar(20) '.'); +EXEC sp_xml_removedocument @h; +GO +~~START~~ +varchar + TaU +~~END~~ + + + + + + +-- test2 +DECLARE @xml nvarchar(2000) = ' + + + John Doe + 50000 + + + Jane Smith + 60000 + +'; +DECLARE @namespace nvarchar(200) = ' +'; +DECLARE @handle INT; +EXEC sp_xml_preparedocument @handle OUTPUT, @xml, @namespace; +SELECT * FROM OPENXML(@handle, '/root/hr:employee', 2) +WITH ( + name nvarchar(50) 'hr:name', + salary int 'fin:salary', + currency nvarchar(10) 'fin:salary/@currency' +); +EXEC sp_xml_removedocument @handle; +GO +~~START~~ +nvarchar#!#int#!#nvarchar +John Doe#!#50000#!#USD +Jane Smith#!#60000#!#USD +~~END~~ + + + + + + +--test3 +DECLARE @xml nvarchar(2000) = ' + + + + Laptop + 999.99 + + + Smartphone + 599.99 + + +'; +DECLARE @namespace nvarchar(200) = ' +'; +DECLARE @handle INT; +EXEC sp_xml_preparedocument @handle OUTPUT, @xml, @namespace; +SELECT * FROM OPENXML(@handle, '/catalog/cat:category/prod:product', 2) +WITH ( + category_name nvarchar(50) '../../@name', + product_name nvarchar(50) 'prod:name', + price decimal(10,2) 'prod:price' +); +EXEC sp_xml_removedocument @handle; +GO +~~START~~ +nvarchar#!#nvarchar#!#numeric +#!#Laptop#!#999.99 +#!#Smartphone#!#599.99 +~~END~~ + + + + + + +--test4 +DECLARE @xml nvarchar(2000) = ' + + + + Alice Johnson + alice@email.com + + + Widget A + Widget B + + +'; +DECLARE @namespace nvarchar(200) = ' +'; +DECLARE @handle INT; +EXEC sp_xml_preparedocument @handle OUTPUT, @xml, @namespace; +SELECT * FROM OPENXML(@handle, '/orders/ord:order/prod:items/prod:item', 2) +WITH ( + order_id int '../../../@id', + customer_name nvarchar(50) '../../../cust:customer/cust:name', + item_name nvarchar(50) '.', + quantity int '@qty' +); +EXEC sp_xml_removedocument @handle; +GO +~~START~~ +int#!#nvarchar#!#nvarchar#!#int +#!##!#Widget A#!#2 +#!##!#Widget B#!#1 +~~END~~ + + + + + + +--test5 +DECLARE @xml nvarchar(2000) = ' + + + New York + + 20 + 65 + + +'; +DECLARE @namespace nvarchar(200) = ' +'; +DECLARE @handle INT; +EXEC sp_xml_preparedocument @handle OUTPUT, @xml, @namespace; +SELECT * FROM OPENXML(@handle, '/weather/loc:city', 2) +WITH ( + city_id varchar(10) '@id', + city_name varchar(50) 'loc:name', + temperature int 'met:conditions/met:temperature', + temp_unit varchar(1) 'met:conditions/met:temperature/@unit', + humidity int 'met:conditions/met:humidity', + reading_date date 'met:conditions/@date' +); +EXEC sp_xml_removedocument @handle; +GO +~~START~~ +varchar#!#varchar#!#int#!#varchar#!#int#!#date +NYC#!#New York#!#20#!#C#!#65#!#2023-01-01 +~~END~~ + + + + + + +--test6 +DECLARE @xml nvarchar(2000) = ' + + + + John Smith + 45 + + + Dr. Brown + Cardiology + + + Hypertension + Lisinopril + + +'; +DECLARE @namespace nvarchar(200) = ' +'; +DECLARE @handle INT; +EXEC sp_xml_preparedocument @handle OUTPUT, @xml, @namespace; +SELECT * FROM OPENXML(@handle, '/medical/pat:record', 2) +WITH ( + record_id int '@id', + patient_name nvarchar(50) 'pat:info/pat:name', + patient_age int 'pat:info/pat:age', + doctor_name nvarchar(50) 'doc:physician/doc:name', + specialty nvarchar(50) 'doc:physician/doc:specialty', + diagnosis nvarchar(100) 'treat:treatment/treat:diagnosis', + medication nvarchar(100) 'treat:treatment/treat:medication' +); +EXEC sp_xml_removedocument @handle; +GO +~~START~~ +int#!#nvarchar#!#int#!#nvarchar#!#nvarchar#!#nvarchar#!#nvarchar +12345#!#John Smith#!#45#!#Dr. Brown#!#Cardiology#!#Hypertension#!#Lisinopril +~~END~~ + + + + + + + +--test7 +DECLARE @xml nvarchar(2000) = ' + + + John Doe + 50000 + + + Jane Smith + 60000 + +'; +DECLARE @namespace nvarchar(200) = ' +'; +DECLARE @handle INT; +EXEC sp_xml_preparedocument @handle OUTPUT, @xml, @namespace; +SELECT * FROM OPENXML(@handle, '/employees/hr:employee', 1) +WITH ( + id int, + department varchar(20), + name varchar(50), + salary int +); +SELECT * FROM OPENXML(@handle, '/employees/hr:employee', 2) +WITH ( + id int, + department varchar(20), + name varchar(50), + salary int +); +EXEC sp_xml_removedocument @handle; +GO +~~START~~ +int#!#varchar#!#varchar#!#int +1#!#IT#!##!# +2#!#HR#!##!# +~~END~~ + +~~START~~ +int#!#varchar#!#varchar#!#int +#!##!##!# +#!##!##!# +~~END~~ + + + + + + +--test8 +DECLARE @xml nvarchar(2000) = ' + + + John Doe + 50000 + + + Jane Smith + 60000 + +'; +DECLARE @namespace nvarchar(200) = ' +'; +DECLARE @handle INT; +EXEC sp_xml_preparedocument @handle OUTPUT, @xml, @namespace; +SELECT * FROM OPENXML(@handle, '/employees/hr:employee', 3) +WITH ( + id int '@id', + department varchar(20) '@department', + name varchar(50) 'hr:name', + salary int 'hr:salary' +); +EXEC sp_xml_removedocument @handle; +GO +~~START~~ +int#!#varchar#!#varchar#!#int +1#!#IT#!#John Doe#!#50000 +2#!#HR#!#Jane Smith#!#60000 +~~END~~ + + + + + + +--test9 +DECLARE @xml nvarchar(2000) = ' + + + + + + + +'; +DECLARE @namespace nvarchar(200) = ' +'; +DECLARE @handle INT; +EXEC sp_xml_preparedocument @handle OUTPUT, @xml, @namespace; +SELECT * FROM OPENXML(@handle, '/root/cust:Customer', 1) +WITH ( + customerid varchar(10), + contactname varchar(50), + country varchar(20) +); +EXEC sp_xml_removedocument @handle; +GO +~~START~~ +varchar#!#varchar#!#varchar +VINET#!#Paul Henriot#!#France +LILAS#!#Carlos Gonzalez#!#Spain +~~END~~ + + + + + + +--test10 +DECLARE @xml nvarchar(2000) = ' + + + 1001 + John + Doe + IT + + + 1002 + Jane + Smith + HR + +'; +DECLARE @namespace nvarchar(200) = ' +'; +DECLARE @handle INT; +EXEC sp_xml_preparedocument @handle OUTPUT, @xml, @namespace; +SELECT * FROM OPENXML(@handle, '/root/emp:Employee', 2) +WITH ( + EmployeeId varchar(10), + FirstName varchar(50), + LastName varchar(50), + Department varchar(20) +); +EXEC sp_xml_removedocument @handle; +GO +~~START~~ +varchar#!#varchar#!#varchar#!#varchar +#!##!##!# +#!##!##!# +~~END~~ + + + + + + +--test11 +DECLARE @xml nvarchar(2000) = ' + + + John Doe + 100.00 + + + Jane Smith + 200.00 + +'; +DECLARE @namespace nvarchar(200) = ' +'; +DECLARE @handle INT; +EXEC sp_xml_preparedocument @handle OUTPUT, @xml, @namespace; +SELECT * FROM OPENXML(@handle, '/root/ord:Order', 3) +WITH ( + id varchar(10), + date datetime, + CustomerName varchar(50), + Total decimal(10,2) +); +EXEC sp_xml_removedocument @handle; +GO +~~START~~ +varchar#!#datetime#!#varchar#!#numeric +1001#!#2023-01-01 00:00:00.0#!##!# +1002#!#2023-01-02 00:00:00.0#!##!# +~~END~~ + + + + + + +--test12 +DECLARE @xml nvarchar(2000) = ' + + + John Doe + + 123 Main St + New York + + + + Jane Smith + + 456 Oak Ave + Los Angeles + + +'; +DECLARE @namespace nvarchar(200) = ' +'; +DECLARE @handle INT; +EXEC sp_xml_preparedocument @handle OUTPUT, @xml, @namespace; +SELECT * FROM OPENXML(@handle, '/root/cust:Customer', 3) +WITH ( + id varchar(10), + Name varchar(50), + Street varchar(100), + City varchar(50) +); +EXEC sp_xml_removedocument @handle; +GO +~~START~~ +varchar#!#varchar#!#varchar#!#varchar +C001#!##!##!# +C002#!##!##!# +~~END~~ + + + + + + +--test13 +DECLARE @xml nvarchar(2000) = ' + + + + 1000.00 + 100.00 + 1100.00 + + + + + 2000.00 + 200.00 + 2200.00 + + +'; +DECLARE @namespace nvarchar(200) = ' +'; +DECLARE @handle INT; +EXEC sp_xml_preparedocument @handle OUTPUT, @xml, @namespace; +SELECT * FROM OPENXML(@handle, '/root/inv:Invoice', 3) +WITH ( + number varchar(10), + type varchar(20), + Amount decimal(10,2), + Tax decimal(10,2), + Total decimal(10,2) +); +EXEC sp_xml_removedocument @handle; +GO +~~START~~ +varchar#!#varchar#!#numeric#!#numeric#!#numeric +INV001#!#Standard#!##!##!# +INV002#!#Express#!##!##!# +~~END~~ + diff --git a/test/JDBC/input/xml/openxml_with_clause-vu-verify.sql b/test/JDBC/input/xml/openxml_with_clause-vu-verify.sql index 25e28affcd2..2a8d356d2fc 100644 --- a/test/JDBC/input/xml/openxml_with_clause-vu-verify.sql +++ b/test/JDBC/input/xml/openxml_with_clause-vu-verify.sql @@ -784,3 +784,440 @@ WHERE s.region_id = r.region_id OR s.region_id IS NULL; EXEC sp_xml_removedocument @xml_doc3; GO +-- With namespaces +--test1 +DECLARE @xml nvarchar(1000) = +' + value1 + value2 +'; +DECLARE @namespace nvarchar(100) = ''; +DECLARE @handle INT; +EXEC sp_xml_preparedocument @handle OUTPUT, @xml, @namespace; +SELECT * FROM OPENXML(@handle, '/root/ns1:child', 3) WITH (child nvarchar(10) '.'); +EXEC sp_xml_removedocument @handle; +GO + +DECLARE @h int; +EXEC sp_xml_preparedocument @h OUTPUT, + N' + + TaU + + ', + ''; + +SELECT * FROM openxml(@h, '/root/b:Elem', 3) + WITH (Col1 varchar(20) '.'); +EXEC sp_xml_removedocument @h; +GO + +-- test2 +DECLARE @xml nvarchar(2000) = ' + + + John Doe + 50000 + + + Jane Smith + 60000 + +'; + +DECLARE @namespace nvarchar(200) = ' +'; + +DECLARE @handle INT; +EXEC sp_xml_preparedocument @handle OUTPUT, @xml, @namespace; + +SELECT * FROM OPENXML(@handle, '/root/hr:employee', 2) +WITH ( + name nvarchar(50) 'hr:name', + salary int 'fin:salary', + currency nvarchar(10) 'fin:salary/@currency' +); + +EXEC sp_xml_removedocument @handle; +GO + +--test3 +DECLARE @xml nvarchar(2000) = ' + + + + Laptop + 999.99 + + + Smartphone + 599.99 + + +'; + +DECLARE @namespace nvarchar(200) = ' +'; + +DECLARE @handle INT; +EXEC sp_xml_preparedocument @handle OUTPUT, @xml, @namespace; + +SELECT * FROM OPENXML(@handle, '/catalog/cat:category/prod:product', 2) +WITH ( + category_name nvarchar(50) '../../@name', + product_name nvarchar(50) 'prod:name', + price decimal(10,2) 'prod:price' +); + +EXEC sp_xml_removedocument @handle; +GO + +--test4 +DECLARE @xml nvarchar(2000) = ' + + + + Alice Johnson + alice@email.com + + + Widget A + Widget B + + +'; + +DECLARE @namespace nvarchar(200) = ' +'; + +DECLARE @handle INT; +EXEC sp_xml_preparedocument @handle OUTPUT, @xml, @namespace; + +SELECT * FROM OPENXML(@handle, '/orders/ord:order/prod:items/prod:item', 2) +WITH ( + order_id int '../../../@id', + customer_name nvarchar(50) '../../../cust:customer/cust:name', + item_name nvarchar(50) '.', + quantity int '@qty' +); + +EXEC sp_xml_removedocument @handle; +GO + +--test5 +DECLARE @xml nvarchar(2000) = ' + + + New York + + 20 + 65 + + +'; + +DECLARE @namespace nvarchar(200) = ' +'; + +DECLARE @handle INT; +EXEC sp_xml_preparedocument @handle OUTPUT, @xml, @namespace; + +SELECT * FROM OPENXML(@handle, '/weather/loc:city', 2) +WITH ( + city_id varchar(10) '@id', + city_name varchar(50) 'loc:name', + temperature int 'met:conditions/met:temperature', + temp_unit varchar(1) 'met:conditions/met:temperature/@unit', + humidity int 'met:conditions/met:humidity', + reading_date date 'met:conditions/@date' +); + +EXEC sp_xml_removedocument @handle; +GO + +--test6 +DECLARE @xml nvarchar(2000) = ' + + + + John Smith + 45 + + + Dr. Brown + Cardiology + + + Hypertension + Lisinopril + + +'; + +DECLARE @namespace nvarchar(200) = ' +'; + +DECLARE @handle INT; +EXEC sp_xml_preparedocument @handle OUTPUT, @xml, @namespace; + +SELECT * FROM OPENXML(@handle, '/medical/pat:record', 2) +WITH ( + record_id int '@id', + patient_name nvarchar(50) 'pat:info/pat:name', + patient_age int 'pat:info/pat:age', + doctor_name nvarchar(50) 'doc:physician/doc:name', + specialty nvarchar(50) 'doc:physician/doc:specialty', + diagnosis nvarchar(100) 'treat:treatment/treat:diagnosis', + medication nvarchar(100) 'treat:treatment/treat:medication' +); + +EXEC sp_xml_removedocument @handle; +GO + +--test7 +DECLARE @xml nvarchar(2000) = ' + + + John Doe + 50000 + + + Jane Smith + 60000 + +'; + +DECLARE @namespace nvarchar(200) = ' +'; + +DECLARE @handle INT; +EXEC sp_xml_preparedocument @handle OUTPUT, @xml, @namespace; + +SELECT * FROM OPENXML(@handle, '/employees/hr:employee', 1) +WITH ( + id int, + department varchar(20), + name varchar(50), + salary int +); + +SELECT * FROM OPENXML(@handle, '/employees/hr:employee', 2) +WITH ( + id int, + department varchar(20), + name varchar(50), + salary int +); + +EXEC sp_xml_removedocument @handle; +GO + +--test8 +DECLARE @xml nvarchar(2000) = ' + + + John Doe + 50000 + + + Jane Smith + 60000 + +'; + +DECLARE @namespace nvarchar(200) = ' +'; + +DECLARE @handle INT; +EXEC sp_xml_preparedocument @handle OUTPUT, @xml, @namespace; + +SELECT * FROM OPENXML(@handle, '/employees/hr:employee', 3) +WITH ( + id int '@id', + department varchar(20) '@department', + name varchar(50) 'hr:name', + salary int 'hr:salary' +); + +EXEC sp_xml_removedocument @handle; +GO + +--test9 +DECLARE @xml nvarchar(2000) = ' + + + + + + + +'; + +DECLARE @namespace nvarchar(200) = ' +'; + +DECLARE @handle INT; +EXEC sp_xml_preparedocument @handle OUTPUT, @xml, @namespace; + +SELECT * FROM OPENXML(@handle, '/root/cust:Customer', 1) +WITH ( + customerid varchar(10), + contactname varchar(50), + country varchar(20) +); + +EXEC sp_xml_removedocument @handle; +GO + +--test10 +DECLARE @xml nvarchar(2000) = ' + + + 1001 + John + Doe + IT + + + 1002 + Jane + Smith + HR + +'; + +DECLARE @namespace nvarchar(200) = ' +'; + +DECLARE @handle INT; +EXEC sp_xml_preparedocument @handle OUTPUT, @xml, @namespace; + +SELECT * FROM OPENXML(@handle, '/root/emp:Employee', 2) +WITH ( + EmployeeId varchar(10), + FirstName varchar(50), + LastName varchar(50), + Department varchar(20) +); + +EXEC sp_xml_removedocument @handle; +GO + +--test11 +DECLARE @xml nvarchar(2000) = ' + + + John Doe + 100.00 + + + Jane Smith + 200.00 + +'; + +DECLARE @namespace nvarchar(200) = ' +'; + +DECLARE @handle INT; +EXEC sp_xml_preparedocument @handle OUTPUT, @xml, @namespace; + +SELECT * FROM OPENXML(@handle, '/root/ord:Order', 3) +WITH ( + id varchar(10), + date datetime, + CustomerName varchar(50), + Total decimal(10,2) +); + +EXEC sp_xml_removedocument @handle; +GO + +--test12 +DECLARE @xml nvarchar(2000) = ' + + + John Doe + + 123 Main St + New York + + + + Jane Smith + + 456 Oak Ave + Los Angeles + + +'; + +DECLARE @namespace nvarchar(200) = ' +'; + +DECLARE @handle INT; +EXEC sp_xml_preparedocument @handle OUTPUT, @xml, @namespace; + +SELECT * FROM OPENXML(@handle, '/root/cust:Customer', 3) +WITH ( + id varchar(10), + Name varchar(50), + Street varchar(100), + City varchar(50) +); + +EXEC sp_xml_removedocument @handle; +GO + +--test13 +DECLARE @xml nvarchar(2000) = ' + + + + 1000.00 + 100.00 + 1100.00 + + + + + 2000.00 + 200.00 + 2200.00 + + +'; + +DECLARE @namespace nvarchar(200) = ' +'; + +DECLARE @handle INT; +EXEC sp_xml_preparedocument @handle OUTPUT, @xml, @namespace; + +SELECT * FROM OPENXML(@handle, '/root/inv:Invoice', 3) +WITH ( + number varchar(10), + type varchar(20), + Amount decimal(10,2), + Tax decimal(10,2), + Total decimal(10,2) +); + +EXEC sp_xml_removedocument @handle; +GO \ No newline at end of file From 4d75cc735f3cfeb1f541536538b1a664aeb5cbdb Mon Sep 17 00:00:00 2001 From: Harsh Dubey Date: Wed, 17 Sep 2025 13:50:51 +0000 Subject: [PATCH 29/40] Refactored code Signed-off-by: Harsh Dubey --- contrib/babelfishpg_tsql/runtime/functions.c | 14 ++++++++------ contrib/babelfishpg_tsql/src/hooks.c | 8 ++++++++ contrib/babelfishpg_tsql/src/pltsql.h | 5 ----- contrib/babelfishpg_tsql/src/procedures.c | 2 +- 4 files changed, 17 insertions(+), 12 deletions(-) diff --git a/contrib/babelfishpg_tsql/runtime/functions.c b/contrib/babelfishpg_tsql/runtime/functions.c index 8d9a3209700..b0aa3a79959 100644 --- a/contrib/babelfishpg_tsql/runtime/functions.c +++ b/contrib/babelfishpg_tsql/runtime/functions.c @@ -210,9 +210,7 @@ void *get_servername_internal(void); void *get_servicename_internal(void); void *get_language(void); void *get_host_id(void); -#ifdef USE_LIBXML void extract_namespaces_from_xml(xmltype *ns_data, char ***ns_names, char ***ns_uris, int *ns_count); -#endif Datum datepart_internal(char *field , Timestamp timestamp , float8 df_tz, bool general_integer_datatype); static HTAB *load_categories_hash(const char *sourcetext, MemoryContext per_query_ctx); @@ -246,6 +244,8 @@ extern PLtsql_execstate *get_outermost_tsql_estate(int *nestlevel); extern char *replace_special_chars_fts_impl(char *input_str); #ifdef USE_LIBXML + +/* This came from backend/utils/adt/xml.c */ struct PgXmlErrorContext { int magic; @@ -5157,7 +5157,6 @@ get_bbf_pivot_tuplestore(const char *sourcetext, return tupstore; } -#ifdef USE_LIBXML /* * extract_namespaces_from_xml * Extracts namespace names and URIs from root node of the given XML data. @@ -5169,7 +5168,8 @@ get_bbf_pivot_tuplestore(const char *sourcetext, void extract_namespaces_from_xml(xmltype *ns_data, char ***ns_names, char ***ns_uris, int *ns_count) { - xmlDocPtr doc; +#ifdef USE_LIBXML + xmlDocPtr doc; xmlNode *root; int index; @@ -5231,5 +5231,7 @@ extract_namespaces_from_xml(xmltype *ns_data, char ***ns_names, char ***ns_uris, if (doc) xmlFreeDoc(doc); -} -#endif \ No newline at end of file +#else +NO_XML_SUPPORT(); +#endif /* not USE_LIBXML */ +} \ No newline at end of file diff --git a/contrib/babelfishpg_tsql/src/hooks.c b/contrib/babelfishpg_tsql/src/hooks.c index 0a15c38449f..cb8bb1e269e 100644 --- a/contrib/babelfishpg_tsql/src/hooks.c +++ b/contrib/babelfishpg_tsql/src/hooks.c @@ -126,6 +126,9 @@ typedef enum PltsqlInitPrivsOptions ERROR_INIT_PRIVS } PltsqlInitPrivsOptions; +extern void get_xml_data_and_namespace_data(int document_id, xmltype **xml_data, xmltype **ns_data); +extern void extract_namespaces_from_xml(xmltype *ns_data, char ***ns_names, char ***ns_uris, int *ns_count); + /***************************************** * General Hooks *****************************************/ @@ -6912,6 +6915,11 @@ openxml_set_namespaces(xmlXPathContext *xpathctx, PgXmlErrorContext *xmlerrcxt, char **ns_uris; int ns_count; + /* + * We will reach here in only two cases, Either when using function XMLTable or OPENXML. + * And since XMLTable syntax is not supported by ANTLR, single dialect check is enough + * to identify that this is for OPENXML. + */ if (sql_dialect != SQL_DIALECT_TSQL) return; diff --git a/contrib/babelfishpg_tsql/src/pltsql.h b/contrib/babelfishpg_tsql/src/pltsql.h index 3e3396da9a0..53c18dee325 100644 --- a/contrib/babelfishpg_tsql/src/pltsql.h +++ b/contrib/babelfishpg_tsql/src/pltsql.h @@ -33,7 +33,6 @@ #include "utils/portal.h" #include "utils/typcache.h" #include "tcop/utility.h" -#include "utils/xml.h" #include "dynavec.h" #include "dynastack.h" @@ -2180,10 +2179,6 @@ extern int pltsql_yyparse(void); /* functions in hooks.c */ extern char *extract_identifier(const char *start, int *last_pos); -extern void get_xml_data_and_namespace_data(int document_id, xmltype **xml_data, xmltype **ns_data); -#ifdef USE_LIBXML -extern void extract_namespaces_from_xml(xmltype *ns_data, char ***ns_names, char ***ns_uris, int *ns_count); -#endif /* functions in pltsql_utils.c */ extern char *gen_createfulltextindex_cmds(const char *table_name, const char *schema_name, const List *column_name, const char *index_name); diff --git a/contrib/babelfishpg_tsql/src/procedures.c b/contrib/babelfishpg_tsql/src/procedures.c index ec5cfcbb68e..69fd1f99942 100644 --- a/contrib/babelfishpg_tsql/src/procedures.c +++ b/contrib/babelfishpg_tsql/src/procedures.c @@ -4942,7 +4942,7 @@ get_xml_data_and_namespace_data(int document_id, xmltype **xml_data, xmltype **n EphemeralNamedRelation enr = NULL; Relation relation; ScanKeyData skey[1]; - TableScanDesc scan; + TableScanDesc scan; HeapTuple tuple; Datum datum; bool isnull; From 6f1376bd449d71f20f5a8607496eceafd81fcefd Mon Sep 17 00:00:00 2001 From: Harsh Dubey Date: Mon, 22 Sep 2025 08:36:56 +0000 Subject: [PATCH 30/40] Added some changes for openxml with clause Signed-off-by: Harsh Dubey --- contrib/babelfishpg_tsql/runtime/functions.c | 2 +- contrib/babelfishpg_tsql/src/procedures.c | 2 +- contrib/babelfishpg_tsql/src/tsqlUnsupportedFeatureHandler.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/contrib/babelfishpg_tsql/runtime/functions.c b/contrib/babelfishpg_tsql/runtime/functions.c index e0d07bc7a6a..ed692cd1b82 100644 --- a/contrib/babelfishpg_tsql/runtime/functions.c +++ b/contrib/babelfishpg_tsql/runtime/functions.c @@ -5185,7 +5185,7 @@ get_bbf_pivot_tuplestore(const char *sourcetext, * The count of extracted namespaces is stored in ns_count. If no namespaces are found, * ns_names and ns_uris are set to NULL and ns_count to 0. */ -static void +void extract_namespaces_from_xml(xmltype *ns_data, char ***ns_names, char ***ns_uris, int *ns_count) { xmlDocPtr doc; diff --git a/contrib/babelfishpg_tsql/src/procedures.c b/contrib/babelfishpg_tsql/src/procedures.c index 814a581ca41..a60a13ab5da 100644 --- a/contrib/babelfishpg_tsql/src/procedures.c +++ b/contrib/babelfishpg_tsql/src/procedures.c @@ -129,7 +129,7 @@ static bool is_supported_case_sp_describe_undeclared_parameters = true; const int XML_HANDLE_COUNTER_START = 0; const int XML_HANDLE_COUNTER_INVALID = INT_MAX / 2; -static int current_xml_handle_counter = XML_HANDLE_COUNTER_INVALID; +static int current_xml_handle_counter = INT_MAX / 2; Bitmapset *active_xml_handles_counter = NULL; static char *xml_handle_temp_table_name = NULL; int get_next_xml_handle_counter(void); diff --git a/contrib/babelfishpg_tsql/src/tsqlUnsupportedFeatureHandler.cpp b/contrib/babelfishpg_tsql/src/tsqlUnsupportedFeatureHandler.cpp index 1d4e29ef92a..bd353c0d721 100644 --- a/contrib/babelfishpg_tsql/src/tsqlUnsupportedFeatureHandler.cpp +++ b/contrib/babelfishpg_tsql/src/tsqlUnsupportedFeatureHandler.cpp @@ -182,7 +182,7 @@ class TsqlUnsupportedFeatureHandlerImpl : public TsqlUnsupportedFeatureHandler antlrcpp::Any visitFunction_call(TSqlParser::Function_callContext *ctx) override; antlrcpp::Any visitAggregate_windowed_function(TSqlParser::Aggregate_windowed_functionContext *ctx) override; antlrcpp::Any visitRowset_function(TSqlParser::Rowset_functionContext *ctx) override { - if (!ctx->open_json() && (!pltsql_enable_linked_servers || !ctx->open_query()) && ctx->open_xml()->WITH()) { + if (!ctx->open_json() && (!pltsql_enable_linked_servers || !ctx->open_query()) && !ctx->open_xml()->WITH()) { handle(INSTR_UNSUPPORTED_TSQL_ROWSET_FUNCTION, "rowset function", getLineAndPos(ctx)); } return visitChildren(ctx); From 8d1f9391aabb7458b0c931f39a3684b8e78a71c3 Mon Sep 17 00:00:00 2001 From: Harsh Dubey Date: Mon, 22 Sep 2025 10:13:13 +0000 Subject: [PATCH 31/40] Deprecated old openxml function Signed-off-by: Harsh Dubey --- contrib/babelfishpg_tsql/runtime/functions.c | 1 - .../sql/sys_function_helpers.sql | 26 ---------- .../babelfishpg_tsql--5.3.0--5.4.0.sql | 14 ++++++ .../src/backend_parser/gram-tsql-rule.y | 48 +++++++++---------- contrib/babelfishpg_tsql/src/procedures.c | 10 ++-- .../src/tsqlUnsupportedFeatureHandler.cpp | 2 +- .../expected_dependency.out | 1 - 7 files changed, 41 insertions(+), 61 deletions(-) diff --git a/contrib/babelfishpg_tsql/runtime/functions.c b/contrib/babelfishpg_tsql/runtime/functions.c index ed692cd1b82..d578e72d24b 100644 --- a/contrib/babelfishpg_tsql/runtime/functions.c +++ b/contrib/babelfishpg_tsql/runtime/functions.c @@ -50,7 +50,6 @@ #include "utils/float.h" #include "utils/xid8.h" #include "utils/xml.h" -#include "utils/xml.h" #include #include "../src/babelfish_version.h" diff --git a/contrib/babelfishpg_tsql/sql/sys_function_helpers.sql b/contrib/babelfishpg_tsql/sql/sys_function_helpers.sql index c5c739d0d63..b10411e748c 100644 --- a/contrib/babelfishpg_tsql/sql/sys_function_helpers.sql +++ b/contrib/babelfishpg_tsql/sql/sys_function_helpers.sql @@ -3022,32 +3022,6 @@ $BODY$ LANGUAGE plpgsql STABLE; -CREATE OR REPLACE FUNCTION sys.babelfish_openxml(IN DocHandle BIGINT) - RETURNS TABLE (XmlData XML) -AS -$BODY$ -DECLARE - XmlDocument$data XML; -BEGIN - - SELECT t.XmlData - INTO STRICT XmlDocument$data - FROM sys$openxml t - WHERE t.DocID = DocHandle; - - RETURN QUERY SELECT XmlDocument$data; - - EXCEPTION - WHEN SQLSTATE '42P01' OR SQLSTATE 'P0002' THEN - RAISE EXCEPTION '%','Could not find prepared statement with handle '||CASE - WHEN DocHandle IS NULL THEN 'null' - ELSE DocHandle::TEXT - END; -END; -$BODY$ -LANGUAGE plpgsql -STABLE; - CREATE OR REPLACE FUNCTION sys.babelfish_parse_to_date(IN p_datestring TEXT, IN p_culture TEXT DEFAULT '') RETURNS DATE diff --git a/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--5.3.0--5.4.0.sql b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--5.3.0--5.4.0.sql index 2555974f3e4..d2009c166ec 100644 --- a/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--5.3.0--5.4.0.sql +++ b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--5.3.0--5.4.0.sql @@ -293,6 +293,20 @@ BEGIN END; $$ LANGUAGE plpgsql IMMUTABLE STRICT PARALLEL SAFE; +DO $$ +DECLARE + exception_message text; +BEGIN + ALTER FUNCTION sys.babelfish_openxml RENAME TO babelfish_openxml_deprecated_in_5_4_0; +EXCEPTION WHEN OTHERS THEN + GET STACKED DIAGNOSTICS + exception_message = MESSAGE_TEXT; + RAISE WARNING '%', exception_message; +END; +$$; + +CALL sys.babelfish_drop_deprecated_object('function', 'sys', 'babelfish_openxml_deprecated_in_5_4_0'); + -- Drops the temporary procedure used by the upgrade script. -- Please have this be one of the last statements executed in this upgrade script. DROP PROCEDURE sys.babelfish_drop_deprecated_object(varchar, varchar, varchar); diff --git a/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-rule.y b/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-rule.y index 0e2ef1c3a96..7aa43f8cc8a 100644 --- a/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-rule.y +++ b/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-rule.y @@ -1814,7 +1814,29 @@ table_ref: relation_expr tsql_table_hint_expr } ; -openxml_expr: OPENXML '(' a_expr ',' a_expr ')' WITH_table TABLE qualified_name opt_alias_clause +openxml_expr: OPENXML '(' a_expr ',' a_expr ')' opt_alias_clause + { + RangeFunction *n = makeNode(RangeFunction); + n->alias = $7; + n->lateral = false; + n->ordinality = false; + n->is_rowsfrom = false; + n->functions = list_make1(list_make2(makeFuncCall(TsqlSystemFuncName("openxml_simple"), list_make2($3, $5), COERCE_EXPLICIT_CALL, -1), NIL)); + /* map to OPENXML_SIMPLE */ + $$ = (Node*) n; + } + | OPENXML '(' a_expr ',' a_expr ',' a_expr ')' opt_alias_clause + { + RangeFunction *n = makeNode(RangeFunction); + n->alias = $9; + n->lateral = false; + n->ordinality = false; + n->is_rowsfrom = false; + n->functions = list_make1(list_make2(makeFuncCall(TsqlSystemFuncName("openxml_simple"), list_make3($3, $5, $7), COERCE_EXPLICIT_CALL, -1), NIL)); + /* map to OPENXML_SIMPLE */ + $$ = (Node*) n; + } + | OPENXML '(' a_expr ',' a_expr ')' WITH_table TABLE qualified_name opt_alias_clause { RangeTableFunc *n = makeNode(RangeTableFunc); n->docexpr = $3; @@ -1893,30 +1915,6 @@ openxml_column_el: } ; -openxml_expr: OPENXML '(' a_expr ',' a_expr ')' opt_alias_clause - { - RangeFunction *n = makeNode(RangeFunction); - n->alias = $7; - n->lateral = false; - n->ordinality = false; - n->is_rowsfrom = false; - n->functions = list_make1(list_make2(makeFuncCall(TsqlSystemFuncName("openxml_simple"), list_make2($3, $5), COERCE_EXPLICIT_CALL, -1), NIL)); - /* map to OPENXML_SIMPLE */ - $$ = (Node*) n; - } - | OPENXML '(' a_expr ',' a_expr ',' a_expr ')' opt_alias_clause - { - RangeFunction *n = makeNode(RangeFunction); - n->alias = $9; - n->lateral = false; - n->ordinality = false; - n->is_rowsfrom = false; - n->functions = list_make1(list_make2(makeFuncCall(TsqlSystemFuncName("openxml_simple"), list_make3($3, $5, $7), COERCE_EXPLICIT_CALL, -1), NIL)); - /* map to OPENXML_SIMPLE */ - $$ = (Node*) n; - } - ; - openjson_expr: OPENJSON '(' a_expr ')' opt_alias_clause { RangeFunction *n = makeNode(RangeFunction); diff --git a/contrib/babelfishpg_tsql/src/procedures.c b/contrib/babelfishpg_tsql/src/procedures.c index a60a13ab5da..a292f8926a3 100644 --- a/contrib/babelfishpg_tsql/src/procedures.c +++ b/contrib/babelfishpg_tsql/src/procedures.c @@ -117,19 +117,15 @@ bool sp_describe_first_result_set_inprogress = false; char *orig_proc_funcname = NULL; static bool is_supported_case_sp_describe_undeclared_parameters = true; -#define Anum_xml_handle_temp_table_document_id 1 -#define Anum_xml_handle_temp_table_xml_data 6 -#define Anum_xml_handle_temp_table_ns_data 7 - #define Anum_xml_handle_temp_table_document_id 1 #define Anum_xml_handle_temp_table_xml_data 6 #define Anum_xml_handle_temp_table_ns_data 7 #define MD5_HASH_LEN 32 -const int XML_HANDLE_COUNTER_START = 0; -const int XML_HANDLE_COUNTER_INVALID = INT_MAX / 2; -static int current_xml_handle_counter = INT_MAX / 2; +#define XML_HANDLE_COUNTER_START 0 +#define XML_HANDLE_COUNTER_INVALID (INT_MAX / 2) +static int current_xml_handle_counter = XML_HANDLE_COUNTER_INVALID; Bitmapset *active_xml_handles_counter = NULL; static char *xml_handle_temp_table_name = NULL; int get_next_xml_handle_counter(void); diff --git a/contrib/babelfishpg_tsql/src/tsqlUnsupportedFeatureHandler.cpp b/contrib/babelfishpg_tsql/src/tsqlUnsupportedFeatureHandler.cpp index bd353c0d721..4c292e8827c 100644 --- a/contrib/babelfishpg_tsql/src/tsqlUnsupportedFeatureHandler.cpp +++ b/contrib/babelfishpg_tsql/src/tsqlUnsupportedFeatureHandler.cpp @@ -182,7 +182,7 @@ class TsqlUnsupportedFeatureHandlerImpl : public TsqlUnsupportedFeatureHandler antlrcpp::Any visitFunction_call(TSqlParser::Function_callContext *ctx) override; antlrcpp::Any visitAggregate_windowed_function(TSqlParser::Aggregate_windowed_functionContext *ctx) override; antlrcpp::Any visitRowset_function(TSqlParser::Rowset_functionContext *ctx) override { - if (!ctx->open_json() && (!pltsql_enable_linked_servers || !ctx->open_query()) && !ctx->open_xml()->WITH()) { + if (!ctx->open_json() && (!pltsql_enable_linked_servers || !ctx->open_query()) && !ctx->open_xml()) { handle(INSTR_UNSUPPORTED_TSQL_ROWSET_FUNCTION, "rowset function", getLineAndPos(ctx)); } return visitChildren(ctx); diff --git a/test/python/expected/upgrade_validation/expected_dependency.out b/test/python/expected/upgrade_validation/expected_dependency.out index b35bc3be547..70248e92ce4 100644 --- a/test/python/expected/upgrade_validation/expected_dependency.out +++ b/test/python/expected/upgrade_validation/expected_dependency.out @@ -132,7 +132,6 @@ Function sys.babelfish_helpdb(character varying) Function sys.babelfish_is_ossp_present() Function sys.babelfish_is_spatial_present() Function sys.babelfish_istime(text) -Function sys.babelfish_openxml(bigint) Function sys.babelfish_parse_helper_to_date(text,boolean,text) Function sys.babelfish_parse_helper_to_datetime(text,boolean,text) Function sys.babelfish_parse_helper_to_time(text,boolean,text) From 64e9c1fa905bb6a7ad5e77090877ba5e9008e969 Mon Sep 17 00:00:00 2001 From: Harsh Dubey Date: Mon, 22 Sep 2025 10:39:54 +0000 Subject: [PATCH 32/40] Rerun workflows Signed-off-by: Harsh Dubey From 1f67d96344a846ad1b2c49317c59df75b56b13de Mon Sep 17 00:00:00 2001 From: Harsh Dubey Date: Mon, 22 Sep 2025 12:11:35 +0000 Subject: [PATCH 33/40] Rerun workflows Signed-off-by: Harsh Dubey From 6b33409f36a4921e298f68ec7ee69062e6f930d7 Mon Sep 17 00:00:00 2001 From: Harsh Dubey Date: Mon, 22 Sep 2025 17:02:17 +0000 Subject: [PATCH 34/40] Refactor code Signed-off-by: Harsh Dubey --- contrib/babelfishpg_tsql/src/hooks.c | 4 ++-- contrib/babelfishpg_tsql/src/procedures.c | 12 +++++++++--- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/contrib/babelfishpg_tsql/src/hooks.c b/contrib/babelfishpg_tsql/src/hooks.c index b9cd45cdb62..3c6001b4f10 100644 --- a/contrib/babelfishpg_tsql/src/hooks.c +++ b/contrib/babelfishpg_tsql/src/hooks.c @@ -7033,7 +7033,7 @@ fetch_table_schema(RangeVar *relation, Node *flag) } else { - colname = NameStr(att->attname); + colname = pstrdup(NameStr(att->attname)); } /* Create a column definition */ @@ -7085,7 +7085,7 @@ pre_transform_openxml_columns(ParseState *pstate, RangeTableFunc *rtf) rtf->namespaces = NIL; rtf->docexpr = NULL; - /* Storing doc_id in the res->name field */ + /* Storing doc_id in the rtf->namespaces field */ res->name = pstrdup("openxml_doc_id"); res->name_location = -1; res->indirection = NIL; diff --git a/contrib/babelfishpg_tsql/src/procedures.c b/contrib/babelfishpg_tsql/src/procedures.c index a292f8926a3..87b8048f565 100644 --- a/contrib/babelfishpg_tsql/src/procedures.c +++ b/contrib/babelfishpg_tsql/src/procedures.c @@ -5067,14 +5067,20 @@ tsql_openxml_get_colpattern(PG_FUNCTION_ARGS) { char *xpath_expr; int flag = PG_GETARG_INT32(1); - char *colname = text_to_cstring(PG_GETARG_TEXT_PP(0)); + char *colname; /* Check if colname is NULL or empty */ - if (colname == NULL || strlen(colname) == 0) + if (PG_ARGISNULL(0)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("Column name cannot be NULL for OPENXML"))); + + colname = text_to_cstring(PG_GETARG_TEXT_PP(0)); + if (strlen(colname) == 0) { ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("Column name cannot be NULL or empty for OPENXML"))); + errmsg("Column name cannot be empty for OPENXML"))); } /* Check for negative flag values */ From 3562c0c15a277f74d789ad81c501c4a8922bba98 Mon Sep 17 00:00:00 2001 From: Harsh Dubey Date: Tue, 23 Sep 2025 15:52:43 +0000 Subject: [PATCH 35/40] Added tests for openxml functions Signed-off-by: Harsh Dubey --- .../openxml_with_clause-vu-cleanup.out | 6 + .../openxml_with_clause-vu-prepare.out | 24 +++ .../openxml_with_clause-vu-verify.out | 143 ++++++++++++++++++ .../xml/openxml_with_clause-vu-cleanup.sql | 6 + .../xml/openxml_with_clause-vu-prepare.sql | 24 +++ .../xml/openxml_with_clause-vu-verify.sql | 57 +++++++ .../expected_dependency.out | 2 - 7 files changed, 260 insertions(+), 2 deletions(-) diff --git a/test/JDBC/expected/openxml_with_clause-vu-cleanup.out b/test/JDBC/expected/openxml_with_clause-vu-cleanup.out index 1b4137b427c..fd22e1cb4c5 100644 --- a/test/JDBC/expected/openxml_with_clause-vu-cleanup.out +++ b/test/JDBC/expected/openxml_with_clause-vu-cleanup.out @@ -21,3 +21,9 @@ GO DROP TABLE regions; GO + +DROP VIEW openxml_column_patterns +GO + +DROP VIEW openxml_documents +GO diff --git a/test/JDBC/expected/openxml_with_clause-vu-prepare.out b/test/JDBC/expected/openxml_with_clause-vu-prepare.out index a1946dd0a00..d1ebe46f7d0 100644 --- a/test/JDBC/expected/openxml_with_clause-vu-prepare.out +++ b/test/JDBC/expected/openxml_with_clause-vu-prepare.out @@ -45,3 +45,27 @@ GO CREATE TABLE regions (region_id INT, region_name VARCHAR(50)); GO + +-- View for col pattern generation and xml doc retrieval +CREATE VIEW openxml_column_patterns AS +SELECT + column_name, + flag, + sys.tsql_openxml_get_colpattern(column_name, flag) AS xpath_pattern +FROM ( + VALUES + ('id', 0), ('id', 1), ('id', 2), ('id', 3), + ('name', 0), ('name', 1), ('name', 2), ('name', 3), + ('value', 0), ('value', 1), ('value', 2), ('value', 3) +) AS patterns(column_name, flag); +GO + +CREATE VIEW openxml_documents AS +SELECT + document_id, + sys.tsql_openxml_get_xmldoc(document_id) AS xml_document +FROM ( + SELECT generate_series(1, 100) AS document_id +) AS doc_ids +WHERE sys.tsql_openxml_get_xmldoc(document_id) IS NOT NULL; +GO diff --git a/test/JDBC/expected/openxml_with_clause-vu-verify.out b/test/JDBC/expected/openxml_with_clause-vu-verify.out index 86f26b4b80f..d4a11932dbe 100644 --- a/test/JDBC/expected/openxml_with_clause-vu-verify.out +++ b/test/JDBC/expected/openxml_with_clause-vu-verify.out @@ -1504,3 +1504,146 @@ INV001#!#Standard#!##!##!# INV002#!#Express#!##!##!# ~~END~~ + +-- Tests for tsql_openxml_get_colpattern and tsql_openxml_get_xmldoc +-- Test basic flag patterns +SELECT sys.tsql_openxml_get_colpattern('name', 0); +GO +~~START~~ +nvarchar +@name +~~END~~ + + +SELECT sys.tsql_openxml_get_colpattern('name', 1); +GO +~~START~~ +nvarchar +@name +~~END~~ + + +SELECT sys.tsql_openxml_get_colpattern('name', 2); +GO +~~START~~ +nvarchar +name +~~END~~ + + +SELECT sys.tsql_openxml_get_colpattern('name', 3); +GO +~~START~~ +nvarchar +name|@name +~~END~~ + + +-- Test flag normalization (mod 4) +SELECT sys.tsql_openxml_get_colpattern('id', 4) +GO +~~START~~ +nvarchar +@id +~~END~~ + + +SELECT sys.tsql_openxml_get_colpattern('id', 5); +GO +~~START~~ +nvarchar +@id +~~END~~ + + +SELECT sys.tsql_openxml_get_colpattern('id', 6); +GO +~~START~~ +nvarchar +id +~~END~~ + + +SELECT sys.tsql_openxml_get_colpattern('id', 7); +GO +~~START~~ +nvarchar +id|@id +~~END~~ + + +-- Test error and null cases +SELECT sys.tsql_openxml_get_colpattern(NULL, 1); +GO +~~START~~ +nvarchar + +~~END~~ + + +SELECT sys.tsql_openxml_get_colpattern('', 1); +GO +~~START~~ +nvarchar +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Column name cannot be empty for OPENXML)~~ + + +SELECT sys.tsql_openxml_get_colpattern('name', -1); +GO +~~START~~ +nvarchar +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Invalid flag value -1 for OPENXML)~~ + + +-- Test with valid document handle +DECLARE @doc_handle INT; +EXEC sp_xml_preparedocument @doc_handle OUTPUT, 'test'; +SELECT sys.tsql_openxml_get_xmldoc(@doc_handle); +EXEC sp_xml_removedocument @doc_handle; +GO +~~START~~ +xml +test +~~END~~ + + +-- Test with invalid or NULL handle +SELECT sys.tsql_openxml_get_xmldoc(999); +GO +~~START~~ +xml +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Could not find prepared statement with handle 999.)~~ + +SELECT sys.tsql_openxml_get_xmldoc(NULL); +GO +~~START~~ +xml + +~~END~~ + + +-- Tests for views for col pattern and xml doc generation +SELECT * FROM openxml_column_patterns WHERE flag = 3; +GO +~~START~~ +varchar#!#int#!#nvarchar +id#!#3#!#id|@id +name#!#3#!#name|@name +value#!#3#!#value|@value +~~END~~ + + +SELECT document_id FROM openxml_documents; +GO +~~START~~ +int +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Could not find prepared statement with handle 1.)~~ + diff --git a/test/JDBC/input/xml/openxml_with_clause-vu-cleanup.sql b/test/JDBC/input/xml/openxml_with_clause-vu-cleanup.sql index 40e755efb27..36765cdc337 100644 --- a/test/JDBC/input/xml/openxml_with_clause-vu-cleanup.sql +++ b/test/JDBC/input/xml/openxml_with_clause-vu-cleanup.sql @@ -20,4 +20,10 @@ DROP TABLE person_table; GO DROP TABLE regions; +GO + +DROP VIEW openxml_column_patterns +GO + +DROP VIEW openxml_documents GO \ No newline at end of file diff --git a/test/JDBC/input/xml/openxml_with_clause-vu-prepare.sql b/test/JDBC/input/xml/openxml_with_clause-vu-prepare.sql index a1946dd0a00..888669fad94 100644 --- a/test/JDBC/input/xml/openxml_with_clause-vu-prepare.sql +++ b/test/JDBC/input/xml/openxml_with_clause-vu-prepare.sql @@ -45,3 +45,27 @@ GO CREATE TABLE regions (region_id INT, region_name VARCHAR(50)); GO + +-- View for col pattern generation and xml doc retrieval +CREATE VIEW openxml_column_patterns AS +SELECT + column_name, + flag, + sys.tsql_openxml_get_colpattern(column_name, flag) AS xpath_pattern +FROM ( + VALUES + ('id', 0), ('id', 1), ('id', 2), ('id', 3), + ('name', 0), ('name', 1), ('name', 2), ('name', 3), + ('value', 0), ('value', 1), ('value', 2), ('value', 3) +) AS patterns(column_name, flag); +GO + +CREATE VIEW openxml_documents AS +SELECT + document_id, + sys.tsql_openxml_get_xmldoc(document_id) AS xml_document +FROM ( + SELECT generate_series(1, 100) AS document_id +) AS doc_ids +WHERE sys.tsql_openxml_get_xmldoc(document_id) IS NOT NULL; +GO \ No newline at end of file diff --git a/test/JDBC/input/xml/openxml_with_clause-vu-verify.sql b/test/JDBC/input/xml/openxml_with_clause-vu-verify.sql index 2a8d356d2fc..0d83ce32f8e 100644 --- a/test/JDBC/input/xml/openxml_with_clause-vu-verify.sql +++ b/test/JDBC/input/xml/openxml_with_clause-vu-verify.sql @@ -1220,4 +1220,61 @@ WITH ( ); EXEC sp_xml_removedocument @handle; +GO + +-- Tests for tsql_openxml_get_colpattern and tsql_openxml_get_xmldoc +-- Test basic flag patterns +SELECT sys.tsql_openxml_get_colpattern('name', 0); +GO + +SELECT sys.tsql_openxml_get_colpattern('name', 1); +GO + +SELECT sys.tsql_openxml_get_colpattern('name', 2); +GO + +SELECT sys.tsql_openxml_get_colpattern('name', 3); +GO + +-- Test flag normalization (mod 4) +SELECT sys.tsql_openxml_get_colpattern('id', 4) +GO + +SELECT sys.tsql_openxml_get_colpattern('id', 5); +GO + +SELECT sys.tsql_openxml_get_colpattern('id', 6); +GO + +SELECT sys.tsql_openxml_get_colpattern('id', 7); +GO + +-- Test error and null cases +SELECT sys.tsql_openxml_get_colpattern(NULL, 1); +GO + +SELECT sys.tsql_openxml_get_colpattern('', 1); +GO + +SELECT sys.tsql_openxml_get_colpattern('name', -1); +GO + +-- Test with valid document handle +DECLARE @doc_handle INT; +EXEC sp_xml_preparedocument @doc_handle OUTPUT, 'test'; +SELECT sys.tsql_openxml_get_xmldoc(@doc_handle); +EXEC sp_xml_removedocument @doc_handle; +GO + +-- Test with invalid or NULL handle +SELECT sys.tsql_openxml_get_xmldoc(999); +GO +SELECT sys.tsql_openxml_get_xmldoc(NULL); +GO + +-- Tests for views for col pattern and xml doc generation +SELECT * FROM openxml_column_patterns WHERE flag = 3; +GO + +SELECT document_id FROM openxml_documents; GO \ No newline at end of file diff --git a/test/python/expected/upgrade_validation/expected_dependency.out b/test/python/expected/upgrade_validation/expected_dependency.out index 70248e92ce4..d650dba0443 100644 --- a/test/python/expected/upgrade_validation/expected_dependency.out +++ b/test/python/expected/upgrade_validation/expected_dependency.out @@ -714,8 +714,6 @@ Function sys.tsql_get_constraintdef(oid) Function sys.tsql_get_expr(text,oid) Function sys.tsql_get_functiondef(oid) Function sys.tsql_get_returntypmodvalue(oid) -Function sys.tsql_openxml_get_colpattern(text,integer) -Function sys.tsql_openxml_get_xmldoc(integer) Function sys.tsql_query_to_json_ffunc(internal) Function sys.tsql_query_to_json_sfunc(internal,anyelement,integer,boolean,boolean,text) Function sys.tsql_query_to_xml_ffunc(internal) From 463243acc24c2f6cd3279a2e1593646f0e7557e9 Mon Sep 17 00:00:00 2001 From: Harsh Dubey Date: Tue, 23 Sep 2025 16:49:27 +0000 Subject: [PATCH 36/40] Fixing failures Signed-off-by: Harsh Dubey --- .../openxml_with_clause-vu-prepare.out | 19 ++----------------- .../openxml_with_clause-vu-verify.out | 3 --- .../xml/openxml_with_clause-vu-prepare.sql | 19 ++----------------- 3 files changed, 4 insertions(+), 37 deletions(-) diff --git a/test/JDBC/expected/openxml_with_clause-vu-prepare.out b/test/JDBC/expected/openxml_with_clause-vu-prepare.out index d1ebe46f7d0..314a7add800 100644 --- a/test/JDBC/expected/openxml_with_clause-vu-prepare.out +++ b/test/JDBC/expected/openxml_with_clause-vu-prepare.out @@ -48,24 +48,9 @@ GO -- View for col pattern generation and xml doc retrieval CREATE VIEW openxml_column_patterns AS -SELECT - column_name, - flag, - sys.tsql_openxml_get_colpattern(column_name, flag) AS xpath_pattern -FROM ( - VALUES - ('id', 0), ('id', 1), ('id', 2), ('id', 3), - ('name', 0), ('name', 1), ('name', 2), ('name', 3), - ('value', 0), ('value', 1), ('value', 2), ('value', 3) -) AS patterns(column_name, flag); +SELECT 'id' as column_name, 0 as flag, sys.tsql_openxml_get_colpattern('id', 0) AS xpath_pattern GO CREATE VIEW openxml_documents AS -SELECT - document_id, - sys.tsql_openxml_get_xmldoc(document_id) AS xml_document -FROM ( - SELECT generate_series(1, 100) AS document_id -) AS doc_ids -WHERE sys.tsql_openxml_get_xmldoc(document_id) IS NOT NULL; +SELECT 1 as document_id, sys.tsql_openxml_get_xmldoc(1) AS xml_document; GO diff --git a/test/JDBC/expected/openxml_with_clause-vu-verify.out b/test/JDBC/expected/openxml_with_clause-vu-verify.out index d4a11932dbe..a48e0a4c6d1 100644 --- a/test/JDBC/expected/openxml_with_clause-vu-verify.out +++ b/test/JDBC/expected/openxml_with_clause-vu-verify.out @@ -1633,9 +1633,6 @@ SELECT * FROM openxml_column_patterns WHERE flag = 3; GO ~~START~~ varchar#!#int#!#nvarchar -id#!#3#!#id|@id -name#!#3#!#name|@name -value#!#3#!#value|@value ~~END~~ diff --git a/test/JDBC/input/xml/openxml_with_clause-vu-prepare.sql b/test/JDBC/input/xml/openxml_with_clause-vu-prepare.sql index 888669fad94..42c559250fe 100644 --- a/test/JDBC/input/xml/openxml_with_clause-vu-prepare.sql +++ b/test/JDBC/input/xml/openxml_with_clause-vu-prepare.sql @@ -48,24 +48,9 @@ GO -- View for col pattern generation and xml doc retrieval CREATE VIEW openxml_column_patterns AS -SELECT - column_name, - flag, - sys.tsql_openxml_get_colpattern(column_name, flag) AS xpath_pattern -FROM ( - VALUES - ('id', 0), ('id', 1), ('id', 2), ('id', 3), - ('name', 0), ('name', 1), ('name', 2), ('name', 3), - ('value', 0), ('value', 1), ('value', 2), ('value', 3) -) AS patterns(column_name, flag); +SELECT 'id' as column_name, 0 as flag, sys.tsql_openxml_get_colpattern('id', 0) AS xpath_pattern GO CREATE VIEW openxml_documents AS -SELECT - document_id, - sys.tsql_openxml_get_xmldoc(document_id) AS xml_document -FROM ( - SELECT generate_series(1, 100) AS document_id -) AS doc_ids -WHERE sys.tsql_openxml_get_xmldoc(document_id) IS NOT NULL; +SELECT 1 as document_id, sys.tsql_openxml_get_xmldoc(1) AS xml_document; GO \ No newline at end of file From 2076c4f00d64500ec6837cb9afdd5dec893e161f Mon Sep 17 00:00:00 2001 From: Harsh Dubey Date: Tue, 23 Sep 2025 19:03:59 +0000 Subject: [PATCH 37/40] Added the openxml before 17_7 files Signed-off-by: Harsh Dubey --- ...xml_with_clause-before-17_7-vu-cleanup.out | 37 + ...xml_with_clause-before-17_7-vu-prepare.out | 64 + ...nxml_with_clause-before-17_7-vu-verify.out | 1644 +++++++++++++++++ ...xml_with_clause-before-17_7-vu-cleanup.sql | 29 + ...xml_with_clause-before-17_7-vu-prepare.sql | 56 + ...nxml_with_clause-before-17_7-vu-verify.sql | 1280 +++++++++++++ test/JDBC/upgrade/13_4/schedule | 2 +- test/JDBC/upgrade/13_5/schedule | 2 +- test/JDBC/upgrade/13_6/schedule | 2 +- test/JDBC/upgrade/13_7/schedule | 2 +- test/JDBC/upgrade/13_8/schedule | 2 +- test/JDBC/upgrade/13_9/schedule | 2 +- test/JDBC/upgrade/14_10/schedule | 2 +- test/JDBC/upgrade/14_11/schedule | 2 +- test/JDBC/upgrade/14_12/schedule | 2 +- test/JDBC/upgrade/14_13/schedule | 2 +- test/JDBC/upgrade/14_15/schedule | 2 +- test/JDBC/upgrade/14_18/schedule | 2 +- test/JDBC/upgrade/14_3/schedule | 2 +- test/JDBC/upgrade/14_5/schedule | 2 +- test/JDBC/upgrade/14_6/schedule | 2 +- test/JDBC/upgrade/14_7/schedule | 2 +- test/JDBC/upgrade/14_8/schedule | 2 +- test/JDBC/upgrade/14_9/schedule | 2 +- test/JDBC/upgrade/15_1/schedule | 2 +- test/JDBC/upgrade/15_10/schedule | 2 +- test/JDBC/upgrade/15_12/schedule | 2 +- test/JDBC/upgrade/15_13/schedule | 2 +- test/JDBC/upgrade/15_14/schedule | 2 +- test/JDBC/upgrade/15_15/schedule | 2 +- test/JDBC/upgrade/15_2/schedule | 2 +- test/JDBC/upgrade/15_3/schedule | 2 +- test/JDBC/upgrade/15_4/schedule | 2 +- test/JDBC/upgrade/15_5/schedule | 2 +- test/JDBC/upgrade/15_6/schedule | 2 +- test/JDBC/upgrade/15_7/schedule | 2 +- test/JDBC/upgrade/15_8/schedule | 2 +- test/JDBC/upgrade/16_1/schedule | 2 +- test/JDBC/upgrade/16_10/schedule | 2 +- test/JDBC/upgrade/16_11/schedule | 2 +- test/JDBC/upgrade/16_2/schedule | 2 +- test/JDBC/upgrade/16_3/schedule | 2 +- test/JDBC/upgrade/16_4/schedule | 2 +- test/JDBC/upgrade/16_6/schedule | 2 +- test/JDBC/upgrade/16_8/schedule | 2 +- test/JDBC/upgrade/16_9/schedule | 2 +- test/JDBC/upgrade/17_4/schedule | 2 +- test/JDBC/upgrade/17_5/schedule | 2 +- test/JDBC/upgrade/17_6/schedule | 2 +- .../expected_create.out | 4 - 50 files changed, 3153 insertions(+), 47 deletions(-) create mode 100644 test/JDBC/expected/openxml_with_clause-before-17_7-vu-cleanup.out create mode 100644 test/JDBC/expected/openxml_with_clause-before-17_7-vu-prepare.out create mode 100644 test/JDBC/expected/openxml_with_clause-before-17_7-vu-verify.out create mode 100644 test/JDBC/input/xml/openxml_with_clause-before-17_7-vu-cleanup.sql create mode 100644 test/JDBC/input/xml/openxml_with_clause-before-17_7-vu-prepare.sql create mode 100644 test/JDBC/input/xml/openxml_with_clause-before-17_7-vu-verify.sql diff --git a/test/JDBC/expected/openxml_with_clause-before-17_7-vu-cleanup.out b/test/JDBC/expected/openxml_with_clause-before-17_7-vu-cleanup.out new file mode 100644 index 00000000000..e70e4ffb139 --- /dev/null +++ b/test/JDBC/expected/openxml_with_clause-before-17_7-vu-cleanup.out @@ -0,0 +1,37 @@ +DROP TABLE test_openxml_table; +GO + +DROP TABLE test_openxml_table_2; +GO + +DROP TABLE very_long_table_name_that_exceeds_sixty_four_characters_limit_test; +GO + +DROP TABLE test_long_columns; +GO + +DROP TABLE mixed_length_names; +GO + +DROP TABLE employee_defaults; +GO + +DROP TABLE person_table; +GO + +DROP TABLE regions; +GO + +DROP VIEW openxml_column_patterns +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: view "openxml_column_patterns" does not exist)~~ + + +DROP VIEW openxml_documents +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: view "openxml_documents" does not exist)~~ + diff --git a/test/JDBC/expected/openxml_with_clause-before-17_7-vu-prepare.out b/test/JDBC/expected/openxml_with_clause-before-17_7-vu-prepare.out new file mode 100644 index 00000000000..341142e60e5 --- /dev/null +++ b/test/JDBC/expected/openxml_with_clause-before-17_7-vu-prepare.out @@ -0,0 +1,64 @@ +CREATE TABLE test_openxml_table(oid char(5), date datetime, amount float); +GO + +CREATE TABLE test_openxml_table_2(oid char(5), Date datetime, amount float); +GO + +CREATE TABLE very_long_table_name_that_exceeds_sixty_four_characters_limit_test ( + id INT, + name VARCHAR(50), + value INT +); +GO + +CREATE TABLE test_long_columns ( + very_long_column_name_that_definitely_exceeds_sixty_four_characters_limit_test INT, + another_extremely_long_column_name_exceeding_standard_limits_for_testing VARCHAR(50), + short_col INT +); +GO + +CREATE TABLE mixed_length_names ( + id INT, + extremely_long_column_name_that_exceeds_the_standard_sixty_four_character_limit_for_identifiers VARCHAR(200), + short VARCHAR(50) +); +GO + +CREATE TABLE employee_defaults ( + id INT IDENTITY(1,1) PRIMARY KEY, + name VARCHAR(50) NOT NULL, + department VARCHAR(20) DEFAULT 'Unknown', + salary DECIMAL(10,2) DEFAULT 0.00, + hire_date DATETIME DEFAULT GETDATE(), + status VARCHAR(10) DEFAULT 'Active', + CHECK (salary >= 0) +); +GO + +CREATE TABLE person_table ( + id INT, + name VARCHAR(50), + age INT +); +GO + +CREATE TABLE regions (region_id INT, region_name VARCHAR(50)); +GO + +-- View for col pattern generation and xml doc retrieval +CREATE VIEW openxml_column_patterns AS +SELECT 'id' as column_name, 0 as flag, sys.tsql_openxml_get_colpattern('id', 0) AS xpath_pattern +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: function sys.tsql_openxml_get_colpattern(unknown, integer) does not exist)~~ + + +CREATE VIEW openxml_documents AS +SELECT 1 as document_id, sys.tsql_openxml_get_xmldoc(1) AS xml_document; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: function sys.tsql_openxml_get_xmldoc(integer) does not exist)~~ + diff --git a/test/JDBC/expected/openxml_with_clause-before-17_7-vu-verify.out b/test/JDBC/expected/openxml_with_clause-before-17_7-vu-verify.out new file mode 100644 index 00000000000..4ed69c8efb9 --- /dev/null +++ b/test/JDBC/expected/openxml_with_clause-before-17_7-vu-verify.out @@ -0,0 +1,1644 @@ + +-- Test plan +-- When Colpattern is given for mapping +DECLARE @docHandle int; +DECLARE @xmlDocument nvarchar(1000); +SET @xmlDocument =N' + + + + + + + + + + + +'; +EXEC sp_xml_preparedocument @docHandle OUTPUT, @xmlDocument; +SELECT * +FROM OPENXML (@docHandle, '/ROOT/Customer/Order/OrderDetail/@ProductID') + WITH ( ProdID int '.', + Qty int '../@Quantity', + OID int '../../@OrderID'); +EXEC sp_xml_removedocument @docHandle; +GO +~~START~~ +int#!#int#!#int +11#!#12#!#10248 +42#!#10#!#10248 +72#!#3#!#10283 +~~END~~ + + + + +-- flag = 0 (default attribute centric) +DECLARE @DocHandle int; +DECLARE @XmlDocument nvarchar(1000); +SET @XmlDocument = N' + + + + + + + + + + + +'; +EXEC sp_xml_preparedocument @DocHandle OUTPUT, @XmlDocument; +SELECT * +FROM OPENXML (@DocHandle, '/ROOT/Customer',0) + WITH (CustomerID varchar(10) , + ContactName varchar(20)); +EXEC sp_xml_removedocument @DocHandle; +GO +~~START~~ +varchar#!#varchar +VINET#!#Paul Henriot +LILAS#!#Carlos Gonzalez +~~END~~ + + + + +-- flag = 1 (attribute centric) +DECLARE @DocHandle int; +DECLARE @XmlDocument nvarchar(1000); +SET @XmlDocument = N' + + + + + + + + + + + +'; +EXEC sp_xml_preparedocument @DocHandle OUTPUT, @XmlDocument; +SELECT * +FROM OPENXML (@DocHandle, '/ROOT/Customer',1) + WITH (CustomerID varchar(10) , + ContactName varchar(20)); +EXEC sp_xml_removedocument @DocHandle; +GO +~~START~~ +varchar#!#varchar +VINET#!#Paul Henriot +LILAS#!#Carlos Gonzalez +~~END~~ + + + + +-- flag = 2 (element centric) +DECLARE @XmlDocumentHandle int; +DECLARE @XmlDocument nvarchar(1000); +SET @XmlDocument = N' + + VINET + Paul Henriot + + + + + + + LILAS + Carlos Gonzalez + + + + +'; +EXEC sp_xml_preparedocument @XmlDocumentHandle OUTPUT, @XmlDocument; +SELECT * +FROM OPENXML (@XmlDocumentHandle, '/ROOT/Customer', 2) + WITH (CustomerID varchar(10), + ContactName varchar(20)); +EXEC sp_xml_removedocument @XmlDocumentHandle; +GO +~~START~~ +varchar#!#varchar +VINET#!#Paul Henriot +LILAS#!#Carlos Gonzalez +~~END~~ + + + + +-- flag = 3 (combines both) +DECLARE @DocHandle int; +DECLARE @XmlDocument nvarchar(1000); +SET @XmlDocument = N' + + + + + + + + LILAS + Carlos Gonzalez + + + + +'; +EXEC sp_xml_preparedocument @DocHandle OUTPUT, @XmlDocument; +SELECT * +FROM OPENXML (@DocHandle, '/ROOT/Customer',3) + WITH (customerid varchar(10), + contactname varchar(20)); +EXEC sp_xml_removedocument @DocHandle; +GO +~~START~~ +varchar#!#varchar +VINET#!#Paul Henriot +LILAS#!#Carlos Gonzalez +~~END~~ + + + + +-- flag = 8 +DECLARE @XmlDocumentHandle int; +DECLARE @XmlDocument nvarchar(1000); +SET @XmlDocument = N' + + VINET + Paul Henriot + + + + + + + + + + +'; +EXEC sp_xml_preparedocument @XmlDocumentHandle OUTPUT, @XmlDocument; +SELECT * +FROM OPENXML (@XmlDocumentHandle, '/ROOT/Customer',8) + WITH (CustomerID varchar(10), + ContactName varchar(20)); +EXEC sp_xml_removedocument @XmlDocumentHandle; +GO +~~START~~ +varchar#!#varchar +#!# +LILAS#!#Carlos Gonzalez +~~END~~ + + + + +-- default flag is 0 +DECLARE @idoc INT, @doc VARCHAR(1000); +SET @doc = N' + + VINET + Paul Henriot + + + + + + + + + + +'; +EXEC sp_xml_preparedocument @idoc OUTPUT, @doc; +SELECT * +FROM OPENXML (@idoc, '/ROOT/Customer') + WITH (CustomerID varchar(10), + ContactName varchar(20)); +EXEC sp_xml_removedocument @idoc; +GO +~~START~~ +varchar#!#varchar +#!# +LILAS#!#Carlos Gonzalez +~~END~~ + + + + + + +-- If tablename is given +DECLARE @docHandle int; +DECLARE @XmlDocument varchar(1000); +SET @xmlDocument = N' + + + Customer was very + satisfied + + + + Important + + + +'; +EXEC sp_xml_preparedocument @docHandle OUTPUT, @xmlDocument; +SELECT * +FROM OPENXML (@docHandle, '/root/Customer/Order', 1) + WITH test_openxml_table; +EXEC sp_xml_removedocument @docHandle; +GO +~~START~~ +char#!#datetime#!#float +O1 #!#1996-01-20 00:00:00.0#!#3.5 +O2 #!#1997-04-30 00:00:00.0#!#13.4 +O3 #!#1999-07-14 00:00:00.0#!#100.0 +O4 #!#1996-01-20 00:00:00.0#!#10000.0 +~~END~~ + + + + +-- If flag value more than 3 +DECLARE @XmlDocumentHandle int; +DECLARE @XmlDocument nvarchar(1000); +SET @XmlDocument = N' + + VINET + Paul Henriot + + + + + + + + + + +'; +EXEC sp_xml_preparedocument @XmlDocumentHandle OUTPUT, @XmlDocument; +SELECT * +FROM OPENXML (@XmlDocumentHandle, '/ROOT/Customer', 4) + WITH (CustomerID varchar(10), + ContactName varchar(20)); +EXEC sp_xml_removedocument @XmlDocumentHandle; +GO +~~START~~ +varchar#!#varchar +#!# +LILAS#!#Carlos Gonzalez +~~END~~ + + + + +DECLARE @XmlDocumentHandle int; +DECLARE @XmlDocument nvarchar(1000); +SET @XmlDocument = N' + + VINET + Paul Henriot + + + + + + + + + + +'; +EXEC sp_xml_preparedocument @XmlDocumentHandle OUTPUT, @XmlDocument; +SELECT * +FROM OPENXML (@XmlDocumentHandle, '/ROOT/Customer', 7) + WITH (CustomerID varchar(10), + ContactName varchar(20)); +EXEC sp_xml_removedocument @XmlDocumentHandle; +GO +~~START~~ +varchar#!#varchar +VINET#!#Paul Henriot +LILAS#!#Carlos Gonzalez +~~END~~ + + + + +-- rowpattern is case sensitive (this gives null) +DECLARE @XmlDocumentHandle int; +DECLARE @XmlDocument nvarchar(1000); +SET @XmlDocument = N' + + VINET + Paul Henriot + + + + + + + + + + +'; +EXEC sp_xml_preparedocument @XmlDocumentHandle OUTPUT, @XmlDocument; +SELECT * +FROM OPENXML (@XmlDocumentHandle, '/root/customer', 4) + WITH (CustomerID varchar(10), + ContactName varchar(20)); +EXEC sp_xml_removedocument @XmlDocumentHandle; +GO +~~START~~ +varchar#!#varchar +~~END~~ + + + + +-- colpattern is case sensitive +DECLARE @DocHandle int; +DECLARE @XmlDocument nvarchar(1000); +SET @XmlDocument = N' + + + + + + + + + + + +'; +EXEC sp_xml_preparedocument @DocHandle OUTPUT, @XmlDocument; +SELECT * +FROM OPENXML (@DocHandle, '/ROOT/Customer',1) + WITH (customerid varchar(10) , + contactname varchar(20)); +EXEC sp_xml_removedocument @DocHandle; +GO +~~START~~ +varchar#!#varchar +#!# +#!# +~~END~~ + + + + +-- negative flag value +DECLARE @XmlDocumentHandle int; +DECLARE @XmlDocument nvarchar(1000); +SET @XmlDocument = N' + + VINET + Paul Henriot + + + + + + + + + + +'; +EXEC sp_xml_preparedocument @XmlDocumentHandle OUTPUT, @XmlDocument; +SELECT * +FROM OPENXML (@XmlDocumentHandle, '/ROOT/Customer', -1) + WITH (CustomerID varchar(10), + ContactName varchar(20)); +EXEC sp_xml_removedocument @XmlDocumentHandle; +GO +~~START~~ +varchar#!#varchar +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Invalid flag value -1 for OPENXML)~~ + + + + +-- Mixed attributes +DECLARE @DocHandle int; +DECLARE @XmlDocument nvarchar(1000); +SET @XmlDocument = N' + + The Great Novel + + John + Author + 4.5 + + + Book House + 2023 + 29.99 + + +'; +EXEC sp_xml_preparedocument @DocHandle OUTPUT, @XmlDocument; +SELECT * +FROM OPENXML (@DocHandle, '/Library/Book', 2) +WITH ( + ISBN varchar(20), + Category varchar(50), + Title varchar(100) 'Title', + AuthorFirstName varchar(50) 'Author/FirstName', + AuthorLastName varchar(50) 'Author/LastName', + Rating decimal(3,1) 'Author/Rating', + Publisher varchar(50) 'Publication/Publisher', + PublishYear int 'Publication/Year', + Price decimal(10,2) 'Publication/Price', + Currency varchar(3) 'Publication/Price/@currency' +); +EXEC sp_xml_removedocument @DocHandle; +GO +~~START~~ +varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#numeric#!#varchar#!#int#!#numeric#!#varchar +#!##!#The Great Novel#!#John#!#Author#!#4.5#!#Book House#!#2023#!#29.99#!#USD +~~END~~ + + + + + + +-- Nested elements +DECLARE @DocHandle int; +DECLARE @XmlDocument nvarchar(2000); +SET @XmlDocument = N' + + + Acme Corp +
123 Business St
+
+ + + Laptop + 2 + 999.99 + 0.10 + + + Mouse + 5 + 24.99 + 0.05 + + +
+
'; +EXEC sp_xml_preparedocument @DocHandle OUTPUT, @XmlDocument; +SELECT * +FROM OPENXML (@DocHandle, '/Invoices/Invoice', 2) +WITH ( + InvoiceID varchar(10), + InvoiceDate date '@Date', + CustomerID varchar(10) 'Customer/@ID', + CustomerName varchar(50) 'Customer/Name', + CustomerAddress varchar(100) 'Customer/Address' +); +SELECT * +FROM OPENXML (@DocHandle, '/Invoices/Invoice/Items/Item', 2) +WITH ( + InvoiceID varchar(10) '../../../@InvoiceID', + SKU varchar(10) '@SKU', + Description varchar(100) 'Description', + Quantity int 'Quantity', + UnitPrice decimal(10,2) 'UnitPrice', + Discount decimal(4,2) 'Discount' +); +EXEC sp_xml_removedocument @DocHandle; +GO +~~START~~ +varchar#!#date#!#varchar#!#varchar#!#varchar +#!#2024-01-15#!#CUST001#!#Acme Corp#!#123 Business St +~~END~~ + +~~START~~ +varchar#!#varchar#!#varchar#!#int#!#numeric#!#numeric +#!#SKU001#!#Laptop#!#2#!#999.99#!#0.10 +#!#SKU002#!#Mouse#!#5#!#24.99#!#0.05 +~~END~~ + + + + + + + + + +-- Basic example which gives customer, order, product details +DECLARE @DocHandle int; +DECLARE @XmlDocument nvarchar(1000); +SET @XmlDocument = N' + + + + + + + + + + + +'; +EXEC sp_xml_preparedocument @DocHandle OUTPUT, @XmlDocument; +SELECT * +FROM OPENXML (@DocHandle, '/ROOT/Customer', 1) +WITH ( + CustomerID varchar(10), + ContactName varchar(50) +); +SELECT * +FROM OPENXML (@DocHandle, '/ROOT/Customer/Order', 1) +WITH ( + OrderID int, + OrderDate date, + CustomerID varchar(10) '../@CustomerID' +); +SELECT * +FROM OPENXML (@DocHandle, '/ROOT/Customer/Order/Product', 1) +WITH ( + OrderID int '../@OrderID', + ProductID varchar(10), + Quantity int, + Price decimal(10,2) +); +EXEC sp_xml_removedocument @DocHandle; +GO +~~START~~ +varchar#!#varchar +C001#!#John Doe +C002#!#Jane Smith +~~END~~ + +~~START~~ +int#!#date#!#varchar +1001#!#2024-01-15#!#C001 +1002#!#2024-01-16#!#C002 +~~END~~ + +~~START~~ +int#!#varchar#!#int#!#numeric +1001#!#P1#!#5#!#100.00 +1001#!#P2#!#3#!#200.00 +1002#!#P3#!#2#!#150.00 +~~END~~ + + + + + + +-- When table name or colname > 64 bytes +-- Test Case 1: Long table name (> 64 bytes) +INSERT INTO very_long_table_name_that_exceeds_sixty_four_characters_limit_test +VALUES (1, 'Test', 100); +DECLARE @xml_doc INT; +EXEC sp_xml_preparedocument @xml_doc OUTPUT, +''; +SELECT * FROM +OPENXML(@xml_doc, '/root/item') +WITH very_long_table_name_that_exceeds_sixty_four_characters_limit_test; +EXEC sp_xml_removedocument @xml_doc; +GO +~~ROW COUNT: 1~~ + +~~START~~ +int#!#varchar#!#int +1#!#John#!#200 +~~END~~ + + + + + + +-- Test Case 2: Long column names (> 64 bytes) +INSERT INTO test_long_columns VALUES (1, 'Test Value', 999); +DECLARE @xml_doc2 INT; +EXEC sp_xml_preparedocument @xml_doc2 OUTPUT, +' + +'; +SELECT * FROM +OPENXML(@xml_doc2, '/data/record') +WITH test_long_columns; +EXEC sp_xml_removedocument @xml_doc2; +GO +~~ROW COUNT: 1~~ + +~~START~~ +int#!#varchar#!#int +123#!#Long Value#!#456 +~~END~~ + + + + +-- Test Case 3: Explicit column definitions with long names +DECLARE @xml_doc3 INT; +EXEC sp_xml_preparedocument @xml_doc3 OUTPUT, +' + +'; +SELECT * FROM +OPENXML(@xml_doc3, '/items/item') WITH ( + very_long_column_name_that_definitely_exceeds_sixty_four_characters_limit_one VARCHAR(100), + another_extremely_long_column_name_that_exceeds_standard_database_limits_two VARCHAR(100) +); +EXEC sp_xml_removedocument @xml_doc3; +GO +~~START~~ +varchar#!#varchar +#!# +~~END~~ + + + + +-- Test Case 4: Mixed long and short names +DECLARE @xml_doc4 INT; +EXEC sp_xml_preparedocument @xml_doc4 OUTPUT, +' + +'; +SELECT * FROM +OPENXML(@xml_doc4, '/test/row') +WITH mixed_length_names; +EXEC sp_xml_removedocument @xml_doc4; +GO +~~START~~ +int#!#varchar#!#varchar +1#!#Long Value Test#!#Short +~~END~~ + + + + + +-- Openxml with table having default constraints +INSERT INTO employee_defaults (name, department, salary) +VALUES ('Test Employee', 'IT', 50000); +DECLARE @xml_doc INT; +EXEC sp_xml_preparedocument @xml_doc OUTPUT, +' + + + +'; +SELECT * FROM +OPENXML(@xml_doc, '/employees/emp') WITH employee_defaults; +EXEC sp_xml_removedocument @xml_doc; +GO +~~ROW COUNT: 1~~ + +~~START~~ +varchar#!#varchar#!#numeric#!#datetime#!#varchar +John Smith#!#HR#!##!##!# +Jane Doe#!##!#75000.00#!##!# +Bob Wilson#!##!##!##!# +~~END~~ + + +-- Test with empty XML document +DECLARE @DocHandle int; +EXEC sp_xml_preparedocument @DocHandle OUTPUT; +SELECT * +FROM OPENXML (@DocHandle, '/', 1) +WITH ( + CustomerID varchar(10), + ContactName varchar(50) +); +EXEC sp_xml_removedocument @DocHandle; +GO +~~START~~ +varchar#!#varchar +~~END~~ + + + + + +-- CROSS APPLY with openxml +DECLARE @DocHandle int; +DECLARE @XmlDocument nvarchar(1000); +SET @XmlDocument = N' + + + + + + + +'; +EXEC sp_xml_preparedocument @DocHandle OUTPUT, @XmlDocument; +SELECT + c.CustomerID, + c.CustomerName, + o.OrderID, + o.OrderDate +FROM + OPENXML(@DocHandle, '/Customers/Customer', 2) + WITH ( + CustomerID int '@ID', + CustomerName varchar(50) '@Name' + ) c +CROSS APPLY + OPENXML(@DocHandle, '/Customers/Customer', 2) + WITH ( + OrderID int '@ID', + OrderDate date '@Date' + ) o; +EXEC sp_xml_removedocument @DocHandle; +GO +~~START~~ +int#!#varchar#!#int#!#date +1#!#John#!#1#!# +1#!#John#!#2#!# +2#!#Jane#!#1#!# +2#!#Jane#!#2#!# +~~END~~ + + + + + +-- cross apply for different row patterns +DECLARE @DocHandle int; +DECLARE @XmlDocument nvarchar(1000); +SET @XmlDocument = N' + + + + + + + +'; +EXEC sp_xml_preparedocument @DocHandle OUTPUT, @XmlDocument; +SELECT + c.CustomerID, + c.CustomerName, + o.OrderID, + o.OrderDate +FROM + OPENXML(@DocHandle, '/Customers/Customer', 2) + WITH ( + CustomerID int '@ID', + CustomerName varchar(50) '@Name' + ) c +CROSS APPLY + OPENXML(@DocHandle, + concat('/Customers/Customer[@ID=', c.CustomerID, ']/Order'), + 2) + WITH ( + OrderID int '@ID', + OrderDate date '@Date' + ) o; +EXEC sp_xml_removedocument @DocHandle; +GO +~~START~~ +int#!#varchar#!#int#!#date +1#!#John#!#1#!#2024-01-01 +1#!#John#!#2#!#2024-01-02 +2#!#Jane#!#3#!#2024-01-03 +~~END~~ + + +-- cross apply for different row patterns +DECLARE @DocHandle int; +DECLARE @XmlDocument nvarchar(1000); +SET @XmlDocument = N''; +EXEC sp_xml_preparedocument @DocHandle OUTPUT, @XmlDocument; +SELECT + c.CustomerID, + c.CustomerName, + o.OrderID, + o.OrderDate +FROM + OPENXML(@DocHandle, '/Customers/Customer', 2) + WITH ( + CustomerID int '@ID', + CustomerName varchar(50) '@Name' + ) c +CROSS APPLY + OPENXML(@DocHandle, + concat('/Customers/Customer[@ID=', c.CustomerID, ']/Order'), + 2) + WITH ( + OrderID int '@ID', + OrderDate date '@Date' + ) o; +EXEC sp_xml_removedocument @DocHandle; +GO +~~START~~ +int#!#varchar#!#int#!#date +~~END~~ + + + + + +-- Basic CROSS APPLY with OPENXML using table reference +INSERT INTO person_table VALUES (1, 'John', 25), (2, 'Jane', 30); +DECLARE @xml_doc INT; +EXEC sp_xml_preparedocument @xml_doc OUTPUT, ''; +SELECT * FROM +(SELECT 1 as id) t +CROSS APPLY OPENXML(@xml_doc, '/root/person') WITH person_table; +EXEC sp_xml_removedocument @xml_doc; +GO +~~ROW COUNT: 2~~ + +~~START~~ +int#!#int#!#varchar#!#int +1#!#1#!#John#!# +1#!#2#!#Jane#!# +~~END~~ + + + + +-- OUTER APPLY +DECLARE @xml_doc2 INT; +EXEC sp_xml_preparedocument @xml_doc2 OUTPUT, +' + + + + + +'; +SELECT + c.customer_id, + c.customer_name, + o.order_id, + o.amount +FROM + OPENXML(@xml_doc2, '/data/customer', 1) WITH ( + customer_id INT, + customer_name VARCHAR(50) + ) c +OUTER APPLY + OPENXML(@xml_doc2, '/data/order', 1) WITH ( + cust_id INT, + order_id INT, + amount DECIMAL(10,2) + ) o; +EXEC sp_xml_removedocument @xml_doc2; +GO +~~START~~ +int#!#varchar#!#int#!#numeric +#!##!#100#!#500.00 +#!##!#101#!#300.00 +#!##!#102#!#200.00 +#!##!#100#!#500.00 +#!##!#101#!#300.00 +#!##!#102#!#200.00 +~~END~~ + + + + + +-- Base table with outer apply openxml +INSERT INTO regions VALUES (1, 'North'), (2, 'South'), (3, 'East'), (4, 'West'); +DECLARE @xml_doc3 INT; +EXEC sp_xml_preparedocument @xml_doc3 OUTPUT, +' + + + + + + + +'; +SELECT + r.region_id, + r.region_name, + s.amount, + s.product +FROM + regions r +OUTER APPLY + OPENXML(@xml_doc3, '/sales/region/sale', 2) WITH ( + region_id INT '../@id', + amount DECIMAL(10,2), + product VARCHAR(50) + ) s +WHERE s.region_id = r.region_id OR s.region_id IS NULL; +EXEC sp_xml_removedocument @xml_doc3; +GO +~~ROW COUNT: 4~~ + +~~START~~ +int#!#varchar#!#numeric#!#varchar +1#!#North#!##!# +1#!#North#!##!# +3#!#East#!##!# +~~END~~ + + +-- With namespaces +--test1 +DECLARE @xml nvarchar(1000) = +' + value1 + value2 +'; +DECLARE @namespace nvarchar(100) = ''; +DECLARE @handle INT; +EXEC sp_xml_preparedocument @handle OUTPUT, @xml, @namespace; +SELECT * FROM OPENXML(@handle, '/root/ns1:child', 3) WITH (child nvarchar(10) '.'); +EXEC sp_xml_removedocument @handle; +GO +~~START~~ +nvarchar +value1 +~~END~~ + + + +DECLARE @h int; +EXEC sp_xml_preparedocument @h OUTPUT, + N' + + TaU + + ', + ''; +SELECT * FROM openxml(@h, '/root/b:Elem', 3) + WITH (Col1 varchar(20) '.'); +EXEC sp_xml_removedocument @h; +GO +~~START~~ +varchar + TaU +~~END~~ + + + + + + +-- test2 +DECLARE @xml nvarchar(2000) = ' + + + John Doe + 50000 + + + Jane Smith + 60000 + +'; +DECLARE @namespace nvarchar(200) = ' +'; +DECLARE @handle INT; +EXEC sp_xml_preparedocument @handle OUTPUT, @xml, @namespace; +SELECT * FROM OPENXML(@handle, '/root/hr:employee', 2) +WITH ( + name nvarchar(50) 'hr:name', + salary int 'fin:salary', + currency nvarchar(10) 'fin:salary/@currency' +); +EXEC sp_xml_removedocument @handle; +GO +~~START~~ +nvarchar#!#int#!#nvarchar +John Doe#!#50000#!#USD +Jane Smith#!#60000#!#USD +~~END~~ + + + + + + +--test3 +DECLARE @xml nvarchar(2000) = ' + + + + Laptop + 999.99 + + + Smartphone + 599.99 + + +'; +DECLARE @namespace nvarchar(200) = ' +'; +DECLARE @handle INT; +EXEC sp_xml_preparedocument @handle OUTPUT, @xml, @namespace; +SELECT * FROM OPENXML(@handle, '/catalog/cat:category/prod:product', 2) +WITH ( + category_name nvarchar(50) '../../@name', + product_name nvarchar(50) 'prod:name', + price decimal(10,2) 'prod:price' +); +EXEC sp_xml_removedocument @handle; +GO +~~START~~ +nvarchar#!#nvarchar#!#numeric +#!#Laptop#!#999.99 +#!#Smartphone#!#599.99 +~~END~~ + + + + + + +--test4 +DECLARE @xml nvarchar(2000) = ' + + + + Alice Johnson + alice@email.com + + + Widget A + Widget B + + +'; +DECLARE @namespace nvarchar(200) = ' +'; +DECLARE @handle INT; +EXEC sp_xml_preparedocument @handle OUTPUT, @xml, @namespace; +SELECT * FROM OPENXML(@handle, '/orders/ord:order/prod:items/prod:item', 2) +WITH ( + order_id int '../../../@id', + customer_name nvarchar(50) '../../../cust:customer/cust:name', + item_name nvarchar(50) '.', + quantity int '@qty' +); +EXEC sp_xml_removedocument @handle; +GO +~~START~~ +int#!#nvarchar#!#nvarchar#!#int +#!##!#Widget A#!#2 +#!##!#Widget B#!#1 +~~END~~ + + + + + + +--test5 +DECLARE @xml nvarchar(2000) = ' + + + New York + + 20 + 65 + + +'; +DECLARE @namespace nvarchar(200) = ' +'; +DECLARE @handle INT; +EXEC sp_xml_preparedocument @handle OUTPUT, @xml, @namespace; +SELECT * FROM OPENXML(@handle, '/weather/loc:city', 2) +WITH ( + city_id varchar(10) '@id', + city_name varchar(50) 'loc:name', + temperature int 'met:conditions/met:temperature', + temp_unit varchar(1) 'met:conditions/met:temperature/@unit', + humidity int 'met:conditions/met:humidity', + reading_date date 'met:conditions/@date' +); +EXEC sp_xml_removedocument @handle; +GO +~~START~~ +varchar#!#varchar#!#int#!#varchar#!#int#!#date +NYC#!#New York#!#20#!#C#!#65#!#2023-01-01 +~~END~~ + + + + + + +--test6 +DECLARE @xml nvarchar(2000) = ' + + + + John Smith + 45 + + + Dr. Brown + Cardiology + + + Hypertension + Lisinopril + + +'; +DECLARE @namespace nvarchar(200) = ' +'; +DECLARE @handle INT; +EXEC sp_xml_preparedocument @handle OUTPUT, @xml, @namespace; +SELECT * FROM OPENXML(@handle, '/medical/pat:record', 2) +WITH ( + record_id int '@id', + patient_name nvarchar(50) 'pat:info/pat:name', + patient_age int 'pat:info/pat:age', + doctor_name nvarchar(50) 'doc:physician/doc:name', + specialty nvarchar(50) 'doc:physician/doc:specialty', + diagnosis nvarchar(100) 'treat:treatment/treat:diagnosis', + medication nvarchar(100) 'treat:treatment/treat:medication' +); +EXEC sp_xml_removedocument @handle; +GO +~~START~~ +int#!#nvarchar#!#int#!#nvarchar#!#nvarchar#!#nvarchar#!#nvarchar +12345#!#John Smith#!#45#!#Dr. Brown#!#Cardiology#!#Hypertension#!#Lisinopril +~~END~~ + + + + + + + +--test7 +DECLARE @xml nvarchar(2000) = ' + + + John Doe + 50000 + + + Jane Smith + 60000 + +'; +DECLARE @namespace nvarchar(200) = ' +'; +DECLARE @handle INT; +EXEC sp_xml_preparedocument @handle OUTPUT, @xml, @namespace; +SELECT * FROM OPENXML(@handle, '/employees/hr:employee', 1) +WITH ( + id int, + department varchar(20), + name varchar(50), + salary int +); +SELECT * FROM OPENXML(@handle, '/employees/hr:employee', 2) +WITH ( + id int, + department varchar(20), + name varchar(50), + salary int +); +EXEC sp_xml_removedocument @handle; +GO +~~START~~ +int#!#varchar#!#varchar#!#int +1#!#IT#!##!# +2#!#HR#!##!# +~~END~~ + +~~START~~ +int#!#varchar#!#varchar#!#int +#!##!##!# +#!##!##!# +~~END~~ + + + + + + +--test8 +DECLARE @xml nvarchar(2000) = ' + + + John Doe + 50000 + + + Jane Smith + 60000 + +'; +DECLARE @namespace nvarchar(200) = ' +'; +DECLARE @handle INT; +EXEC sp_xml_preparedocument @handle OUTPUT, @xml, @namespace; +SELECT * FROM OPENXML(@handle, '/employees/hr:employee', 3) +WITH ( + id int '@id', + department varchar(20) '@department', + name varchar(50) 'hr:name', + salary int 'hr:salary' +); +EXEC sp_xml_removedocument @handle; +GO +~~START~~ +int#!#varchar#!#varchar#!#int +1#!#IT#!#John Doe#!#50000 +2#!#HR#!#Jane Smith#!#60000 +~~END~~ + + + + + + +--test9 +DECLARE @xml nvarchar(2000) = ' + + + + + + + +'; +DECLARE @namespace nvarchar(200) = ' +'; +DECLARE @handle INT; +EXEC sp_xml_preparedocument @handle OUTPUT, @xml, @namespace; +SELECT * FROM OPENXML(@handle, '/root/cust:Customer', 1) +WITH ( + customerid varchar(10), + contactname varchar(50), + country varchar(20) +); +EXEC sp_xml_removedocument @handle; +GO +~~START~~ +varchar#!#varchar#!#varchar +VINET#!#Paul Henriot#!#France +LILAS#!#Carlos Gonzalez#!#Spain +~~END~~ + + + + + + +--test10 +DECLARE @xml nvarchar(2000) = ' + + + 1001 + John + Doe + IT + + + 1002 + Jane + Smith + HR + +'; +DECLARE @namespace nvarchar(200) = ' +'; +DECLARE @handle INT; +EXEC sp_xml_preparedocument @handle OUTPUT, @xml, @namespace; +SELECT * FROM OPENXML(@handle, '/root/emp:Employee', 2) +WITH ( + EmployeeId varchar(10), + FirstName varchar(50), + LastName varchar(50), + Department varchar(20) +); +EXEC sp_xml_removedocument @handle; +GO +~~START~~ +varchar#!#varchar#!#varchar#!#varchar +#!##!##!# +#!##!##!# +~~END~~ + + + + + + +--test11 +DECLARE @xml nvarchar(2000) = ' + + + John Doe + 100.00 + + + Jane Smith + 200.00 + +'; +DECLARE @namespace nvarchar(200) = ' +'; +DECLARE @handle INT; +EXEC sp_xml_preparedocument @handle OUTPUT, @xml, @namespace; +SELECT * FROM OPENXML(@handle, '/root/ord:Order', 3) +WITH ( + id varchar(10), + date datetime, + CustomerName varchar(50), + Total decimal(10,2) +); +EXEC sp_xml_removedocument @handle; +GO +~~START~~ +varchar#!#datetime#!#varchar#!#numeric +1001#!#2023-01-01 00:00:00.0#!##!# +1002#!#2023-01-02 00:00:00.0#!##!# +~~END~~ + + + + + + +--test12 +DECLARE @xml nvarchar(2000) = ' + + + John Doe + + 123 Main St + New York + + + + Jane Smith + + 456 Oak Ave + Los Angeles + + +'; +DECLARE @namespace nvarchar(200) = ' +'; +DECLARE @handle INT; +EXEC sp_xml_preparedocument @handle OUTPUT, @xml, @namespace; +SELECT * FROM OPENXML(@handle, '/root/cust:Customer', 3) +WITH ( + id varchar(10), + Name varchar(50), + Street varchar(100), + City varchar(50) +); +EXEC sp_xml_removedocument @handle; +GO +~~START~~ +varchar#!#varchar#!#varchar#!#varchar +C001#!##!##!# +C002#!##!##!# +~~END~~ + + + + + + +--test13 +DECLARE @xml nvarchar(2000) = ' + + + + 1000.00 + 100.00 + 1100.00 + + + + + 2000.00 + 200.00 + 2200.00 + + +'; +DECLARE @namespace nvarchar(200) = ' +'; +DECLARE @handle INT; +EXEC sp_xml_preparedocument @handle OUTPUT, @xml, @namespace; +SELECT * FROM OPENXML(@handle, '/root/inv:Invoice', 3) +WITH ( + number varchar(10), + type varchar(20), + Amount decimal(10,2), + Tax decimal(10,2), + Total decimal(10,2) +); +EXEC sp_xml_removedocument @handle; +GO +~~START~~ +varchar#!#varchar#!#numeric#!#numeric#!#numeric +INV001#!#Standard#!##!##!# +INV002#!#Express#!##!##!# +~~END~~ + + +-- Tests for tsql_openxml_get_colpattern and tsql_openxml_get_xmldoc +-- Test basic flag patterns +SELECT sys.tsql_openxml_get_colpattern('name', 0); +GO +~~START~~ +nvarchar +@name +~~END~~ + + +SELECT sys.tsql_openxml_get_colpattern('name', 1); +GO +~~START~~ +nvarchar +@name +~~END~~ + + +SELECT sys.tsql_openxml_get_colpattern('name', 2); +GO +~~START~~ +nvarchar +name +~~END~~ + + +SELECT sys.tsql_openxml_get_colpattern('name', 3); +GO +~~START~~ +nvarchar +name|@name +~~END~~ + + +-- Test flag normalization (mod 4) +SELECT sys.tsql_openxml_get_colpattern('id', 4) +GO +~~START~~ +nvarchar +@id +~~END~~ + + +SELECT sys.tsql_openxml_get_colpattern('id', 5); +GO +~~START~~ +nvarchar +@id +~~END~~ + + +SELECT sys.tsql_openxml_get_colpattern('id', 6); +GO +~~START~~ +nvarchar +id +~~END~~ + + +SELECT sys.tsql_openxml_get_colpattern('id', 7); +GO +~~START~~ +nvarchar +id|@id +~~END~~ + + +-- Test error and null cases +SELECT sys.tsql_openxml_get_colpattern(NULL, 1); +GO +~~START~~ +nvarchar + +~~END~~ + + +SELECT sys.tsql_openxml_get_colpattern('', 1); +GO +~~START~~ +nvarchar +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Column name cannot be empty for OPENXML)~~ + + +SELECT sys.tsql_openxml_get_colpattern('name', -1); +GO +~~START~~ +nvarchar +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Invalid flag value -1 for OPENXML)~~ + + +-- Test with valid document handle +DECLARE @doc_handle INT; +EXEC sp_xml_preparedocument @doc_handle OUTPUT, 'test'; +SELECT sys.tsql_openxml_get_xmldoc(@doc_handle); +EXEC sp_xml_removedocument @doc_handle; +GO +~~START~~ +xml +test +~~END~~ + + +-- Test with invalid or NULL handle +SELECT sys.tsql_openxml_get_xmldoc(999); +GO +~~START~~ +xml +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Could not find prepared statement with handle 999.)~~ + +SELECT sys.tsql_openxml_get_xmldoc(NULL); +GO +~~START~~ +xml + +~~END~~ + + +-- Tests for views for col pattern and xml doc generation +SELECT * FROM openxml_column_patterns WHERE flag = 3; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: relation "openxml_column_patterns" does not exist)~~ + + +SELECT document_id FROM openxml_documents; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: relation "openxml_documents" does not exist)~~ + diff --git a/test/JDBC/input/xml/openxml_with_clause-before-17_7-vu-cleanup.sql b/test/JDBC/input/xml/openxml_with_clause-before-17_7-vu-cleanup.sql new file mode 100644 index 00000000000..36765cdc337 --- /dev/null +++ b/test/JDBC/input/xml/openxml_with_clause-before-17_7-vu-cleanup.sql @@ -0,0 +1,29 @@ +DROP TABLE test_openxml_table; +GO + +DROP TABLE test_openxml_table_2; +GO + +DROP TABLE very_long_table_name_that_exceeds_sixty_four_characters_limit_test; +GO + +DROP TABLE test_long_columns; +GO + +DROP TABLE mixed_length_names; +GO + +DROP TABLE employee_defaults; +GO + +DROP TABLE person_table; +GO + +DROP TABLE regions; +GO + +DROP VIEW openxml_column_patterns +GO + +DROP VIEW openxml_documents +GO \ No newline at end of file diff --git a/test/JDBC/input/xml/openxml_with_clause-before-17_7-vu-prepare.sql b/test/JDBC/input/xml/openxml_with_clause-before-17_7-vu-prepare.sql new file mode 100644 index 00000000000..42c559250fe --- /dev/null +++ b/test/JDBC/input/xml/openxml_with_clause-before-17_7-vu-prepare.sql @@ -0,0 +1,56 @@ +CREATE TABLE test_openxml_table(oid char(5), date datetime, amount float); +GO + +CREATE TABLE test_openxml_table_2(oid char(5), Date datetime, amount float); +GO + +CREATE TABLE very_long_table_name_that_exceeds_sixty_four_characters_limit_test ( + id INT, + name VARCHAR(50), + value INT +); +GO + +CREATE TABLE test_long_columns ( + very_long_column_name_that_definitely_exceeds_sixty_four_characters_limit_test INT, + another_extremely_long_column_name_exceeding_standard_limits_for_testing VARCHAR(50), + short_col INT +); +GO + +CREATE TABLE mixed_length_names ( + id INT, + extremely_long_column_name_that_exceeds_the_standard_sixty_four_character_limit_for_identifiers VARCHAR(200), + short VARCHAR(50) +); +GO + +CREATE TABLE employee_defaults ( + id INT IDENTITY(1,1) PRIMARY KEY, + name VARCHAR(50) NOT NULL, + department VARCHAR(20) DEFAULT 'Unknown', + salary DECIMAL(10,2) DEFAULT 0.00, + hire_date DATETIME DEFAULT GETDATE(), + status VARCHAR(10) DEFAULT 'Active', + CHECK (salary >= 0) +); +GO + +CREATE TABLE person_table ( + id INT, + name VARCHAR(50), + age INT +); +GO + +CREATE TABLE regions (region_id INT, region_name VARCHAR(50)); +GO + +-- View for col pattern generation and xml doc retrieval +CREATE VIEW openxml_column_patterns AS +SELECT 'id' as column_name, 0 as flag, sys.tsql_openxml_get_colpattern('id', 0) AS xpath_pattern +GO + +CREATE VIEW openxml_documents AS +SELECT 1 as document_id, sys.tsql_openxml_get_xmldoc(1) AS xml_document; +GO \ No newline at end of file diff --git a/test/JDBC/input/xml/openxml_with_clause-before-17_7-vu-verify.sql b/test/JDBC/input/xml/openxml_with_clause-before-17_7-vu-verify.sql new file mode 100644 index 00000000000..0d83ce32f8e --- /dev/null +++ b/test/JDBC/input/xml/openxml_with_clause-before-17_7-vu-verify.sql @@ -0,0 +1,1280 @@ +-- Test plan + +-- When Colpattern is given for mapping +DECLARE @docHandle int; +DECLARE @xmlDocument nvarchar(1000); +SET @xmlDocument =N' + + + + + + + + + + + +'; +EXEC sp_xml_preparedocument @docHandle OUTPUT, @xmlDocument; +SELECT * +FROM OPENXML (@docHandle, '/ROOT/Customer/Order/OrderDetail/@ProductID') + WITH ( ProdID int '.', + Qty int '../@Quantity', + OID int '../../@OrderID'); +EXEC sp_xml_removedocument @docHandle; +GO + +-- flag = 0 (default attribute centric) +DECLARE @DocHandle int; +DECLARE @XmlDocument nvarchar(1000); +SET @XmlDocument = N' + + + + + + + + + + + +'; + +EXEC sp_xml_preparedocument @DocHandle OUTPUT, @XmlDocument; + +SELECT * +FROM OPENXML (@DocHandle, '/ROOT/Customer',0) + WITH (CustomerID varchar(10) , + ContactName varchar(20)); +EXEC sp_xml_removedocument @DocHandle; +GO + +-- flag = 1 (attribute centric) +DECLARE @DocHandle int; +DECLARE @XmlDocument nvarchar(1000); +SET @XmlDocument = N' + + + + + + + + + + + +'; + +EXEC sp_xml_preparedocument @DocHandle OUTPUT, @XmlDocument; + +SELECT * +FROM OPENXML (@DocHandle, '/ROOT/Customer',1) + WITH (CustomerID varchar(10) , + ContactName varchar(20)); +EXEC sp_xml_removedocument @DocHandle; +GO + +-- flag = 2 (element centric) +DECLARE @XmlDocumentHandle int; +DECLARE @XmlDocument nvarchar(1000); +SET @XmlDocument = N' + + VINET + Paul Henriot + + + + + + + LILAS + Carlos Gonzalez + + + + +'; + +EXEC sp_xml_preparedocument @XmlDocumentHandle OUTPUT, @XmlDocument; + +SELECT * +FROM OPENXML (@XmlDocumentHandle, '/ROOT/Customer', 2) + WITH (CustomerID varchar(10), + ContactName varchar(20)); +EXEC sp_xml_removedocument @XmlDocumentHandle; +GO + +-- flag = 3 (combines both) +DECLARE @DocHandle int; +DECLARE @XmlDocument nvarchar(1000); +SET @XmlDocument = N' + + + + + + + + LILAS + Carlos Gonzalez + + + + +'; + +EXEC sp_xml_preparedocument @DocHandle OUTPUT, @XmlDocument; + +SELECT * +FROM OPENXML (@DocHandle, '/ROOT/Customer',3) + WITH (customerid varchar(10), + contactname varchar(20)); +EXEC sp_xml_removedocument @DocHandle; +GO + +-- flag = 8 +DECLARE @XmlDocumentHandle int; +DECLARE @XmlDocument nvarchar(1000); +SET @XmlDocument = N' + + VINET + Paul Henriot + + + + + + + + + + +'; + +EXEC sp_xml_preparedocument @XmlDocumentHandle OUTPUT, @XmlDocument; + +SELECT * +FROM OPENXML (@XmlDocumentHandle, '/ROOT/Customer',8) + WITH (CustomerID varchar(10), + ContactName varchar(20)); +EXEC sp_xml_removedocument @XmlDocumentHandle; +GO + +-- default flag is 0 +DECLARE @idoc INT, @doc VARCHAR(1000); +SET @doc = N' + + VINET + Paul Henriot + + + + + + + + + + +'; + +EXEC sp_xml_preparedocument @idoc OUTPUT, @doc; + +SELECT * +FROM OPENXML (@idoc, '/ROOT/Customer') + WITH (CustomerID varchar(10), + ContactName varchar(20)); +EXEC sp_xml_removedocument @idoc; +GO + +-- If tablename is given +DECLARE @docHandle int; +DECLARE @XmlDocument varchar(1000); + +SET @xmlDocument = N' + + + Customer was very + satisfied + + + + Important + + + +'; + +EXEC sp_xml_preparedocument @docHandle OUTPUT, @xmlDocument; + +SELECT * +FROM OPENXML (@docHandle, '/root/Customer/Order', 1) + WITH test_openxml_table; + +EXEC sp_xml_removedocument @docHandle; +GO + +-- If flag value more than 3 +DECLARE @XmlDocumentHandle int; +DECLARE @XmlDocument nvarchar(1000); +SET @XmlDocument = N' + + VINET + Paul Henriot + + + + + + + + + + +'; + +EXEC sp_xml_preparedocument @XmlDocumentHandle OUTPUT, @XmlDocument; + +SELECT * +FROM OPENXML (@XmlDocumentHandle, '/ROOT/Customer', 4) + WITH (CustomerID varchar(10), + ContactName varchar(20)); +EXEC sp_xml_removedocument @XmlDocumentHandle; +GO + +DECLARE @XmlDocumentHandle int; +DECLARE @XmlDocument nvarchar(1000); +SET @XmlDocument = N' + + VINET + Paul Henriot + + + + + + + + + + +'; + +EXEC sp_xml_preparedocument @XmlDocumentHandle OUTPUT, @XmlDocument; + +SELECT * +FROM OPENXML (@XmlDocumentHandle, '/ROOT/Customer', 7) + WITH (CustomerID varchar(10), + ContactName varchar(20)); +EXEC sp_xml_removedocument @XmlDocumentHandle; +GO + +-- rowpattern is case sensitive (this gives null) +DECLARE @XmlDocumentHandle int; +DECLARE @XmlDocument nvarchar(1000); +SET @XmlDocument = N' + + VINET + Paul Henriot + + + + + + + + + + +'; + +EXEC sp_xml_preparedocument @XmlDocumentHandle OUTPUT, @XmlDocument; + +SELECT * +FROM OPENXML (@XmlDocumentHandle, '/root/customer', 4) + WITH (CustomerID varchar(10), + ContactName varchar(20)); +EXEC sp_xml_removedocument @XmlDocumentHandle; +GO + +-- colpattern is case sensitive +DECLARE @DocHandle int; +DECLARE @XmlDocument nvarchar(1000); +SET @XmlDocument = N' + + + + + + + + + + + +'; + +EXEC sp_xml_preparedocument @DocHandle OUTPUT, @XmlDocument; + +SELECT * +FROM OPENXML (@DocHandle, '/ROOT/Customer',1) + WITH (customerid varchar(10) , + contactname varchar(20)); +EXEC sp_xml_removedocument @DocHandle; +GO + +-- negative flag value +DECLARE @XmlDocumentHandle int; +DECLARE @XmlDocument nvarchar(1000); +SET @XmlDocument = N' + + VINET + Paul Henriot + + + + + + + + + + +'; + +EXEC sp_xml_preparedocument @XmlDocumentHandle OUTPUT, @XmlDocument; + +SELECT * +FROM OPENXML (@XmlDocumentHandle, '/ROOT/Customer', -1) + WITH (CustomerID varchar(10), + ContactName varchar(20)); +EXEC sp_xml_removedocument @XmlDocumentHandle; +GO + +-- Mixed attributes +DECLARE @DocHandle int; +DECLARE @XmlDocument nvarchar(1000); +SET @XmlDocument = N' + + The Great Novel + + John + Author + 4.5 + + + Book House + 2023 + 29.99 + + +'; + +EXEC sp_xml_preparedocument @DocHandle OUTPUT, @XmlDocument; + +SELECT * +FROM OPENXML (@DocHandle, '/Library/Book', 2) +WITH ( + ISBN varchar(20), + Category varchar(50), + Title varchar(100) 'Title', + AuthorFirstName varchar(50) 'Author/FirstName', + AuthorLastName varchar(50) 'Author/LastName', + Rating decimal(3,1) 'Author/Rating', + Publisher varchar(50) 'Publication/Publisher', + PublishYear int 'Publication/Year', + Price decimal(10,2) 'Publication/Price', + Currency varchar(3) 'Publication/Price/@currency' +); +EXEC sp_xml_removedocument @DocHandle; +GO + +-- Nested elements +DECLARE @DocHandle int; +DECLARE @XmlDocument nvarchar(2000); +SET @XmlDocument = N' + + + Acme Corp +
123 Business St
+
+ + + Laptop + 2 + 999.99 + 0.10 + + + Mouse + 5 + 24.99 + 0.05 + + +
+
'; + +EXEC sp_xml_preparedocument @DocHandle OUTPUT, @XmlDocument; + +SELECT * +FROM OPENXML (@DocHandle, '/Invoices/Invoice', 2) +WITH ( + InvoiceID varchar(10), + InvoiceDate date '@Date', + CustomerID varchar(10) 'Customer/@ID', + CustomerName varchar(50) 'Customer/Name', + CustomerAddress varchar(100) 'Customer/Address' +); + +SELECT * +FROM OPENXML (@DocHandle, '/Invoices/Invoice/Items/Item', 2) +WITH ( + InvoiceID varchar(10) '../../../@InvoiceID', + SKU varchar(10) '@SKU', + Description varchar(100) 'Description', + Quantity int 'Quantity', + UnitPrice decimal(10,2) 'UnitPrice', + Discount decimal(4,2) 'Discount' +); + +EXEC sp_xml_removedocument @DocHandle; +GO + +-- Basic example which gives customer, order, product details +DECLARE @DocHandle int; +DECLARE @XmlDocument nvarchar(1000); +SET @XmlDocument = N' + + + + + + + + + + + +'; + +EXEC sp_xml_preparedocument @DocHandle OUTPUT, @XmlDocument; + + +SELECT * +FROM OPENXML (@DocHandle, '/ROOT/Customer', 1) +WITH ( + CustomerID varchar(10), + ContactName varchar(50) +); + +SELECT * +FROM OPENXML (@DocHandle, '/ROOT/Customer/Order', 1) +WITH ( + OrderID int, + OrderDate date, + CustomerID varchar(10) '../@CustomerID' +); + + +SELECT * +FROM OPENXML (@DocHandle, '/ROOT/Customer/Order/Product', 1) +WITH ( + OrderID int '../@OrderID', + ProductID varchar(10), + Quantity int, + Price decimal(10,2) +); + +EXEC sp_xml_removedocument @DocHandle; +GO + +-- When table name or colname > 64 bytes + +-- Test Case 1: Long table name (> 64 bytes) +INSERT INTO very_long_table_name_that_exceeds_sixty_four_characters_limit_test +VALUES (1, 'Test', 100); + +DECLARE @xml_doc INT; +EXEC sp_xml_preparedocument @xml_doc OUTPUT, +''; + +SELECT * FROM +OPENXML(@xml_doc, '/root/item') +WITH very_long_table_name_that_exceeds_sixty_four_characters_limit_test; + +EXEC sp_xml_removedocument @xml_doc; +GO + +-- Test Case 2: Long column names (> 64 bytes) +INSERT INTO test_long_columns VALUES (1, 'Test Value', 999); + +DECLARE @xml_doc2 INT; +EXEC sp_xml_preparedocument @xml_doc2 OUTPUT, +' + +'; + + +SELECT * FROM +OPENXML(@xml_doc2, '/data/record') +WITH test_long_columns; + +EXEC sp_xml_removedocument @xml_doc2; +GO + +-- Test Case 3: Explicit column definitions with long names +DECLARE @xml_doc3 INT; +EXEC sp_xml_preparedocument @xml_doc3 OUTPUT, +' + +'; + +SELECT * FROM +OPENXML(@xml_doc3, '/items/item') WITH ( + very_long_column_name_that_definitely_exceeds_sixty_four_characters_limit_one VARCHAR(100), + another_extremely_long_column_name_that_exceeds_standard_database_limits_two VARCHAR(100) +); + +EXEC sp_xml_removedocument @xml_doc3; +GO + +-- Test Case 4: Mixed long and short names +DECLARE @xml_doc4 INT; +EXEC sp_xml_preparedocument @xml_doc4 OUTPUT, +' + +'; + +SELECT * FROM +OPENXML(@xml_doc4, '/test/row') +WITH mixed_length_names; + +EXEC sp_xml_removedocument @xml_doc4; +GO + +-- Openxml with table having default constraints +INSERT INTO employee_defaults (name, department, salary) +VALUES ('Test Employee', 'IT', 50000); + +DECLARE @xml_doc INT; +EXEC sp_xml_preparedocument @xml_doc OUTPUT, +' + + + +'; + +SELECT * FROM +OPENXML(@xml_doc, '/employees/emp') WITH employee_defaults; + +EXEC sp_xml_removedocument @xml_doc; +GO + +-- Test with empty XML document +DECLARE @DocHandle int; +EXEC sp_xml_preparedocument @DocHandle OUTPUT; +SELECT * +FROM OPENXML (@DocHandle, '/', 1) +WITH ( + CustomerID varchar(10), + ContactName varchar(50) +); +EXEC sp_xml_removedocument @DocHandle; +GO + +-- CROSS APPLY with openxml +DECLARE @DocHandle int; +DECLARE @XmlDocument nvarchar(1000); +SET @XmlDocument = N' + + + + + + + +'; + +EXEC sp_xml_preparedocument @DocHandle OUTPUT, @XmlDocument; + +SELECT + c.CustomerID, + c.CustomerName, + o.OrderID, + o.OrderDate +FROM + OPENXML(@DocHandle, '/Customers/Customer', 2) + WITH ( + CustomerID int '@ID', + CustomerName varchar(50) '@Name' + ) c +CROSS APPLY + OPENXML(@DocHandle, '/Customers/Customer', 2) + WITH ( + OrderID int '@ID', + OrderDate date '@Date' + ) o; + +EXEC sp_xml_removedocument @DocHandle; +GO + +-- cross apply for different row patterns +DECLARE @DocHandle int; +DECLARE @XmlDocument nvarchar(1000); +SET @XmlDocument = N' + + + + + + + +'; + +EXEC sp_xml_preparedocument @DocHandle OUTPUT, @XmlDocument; + +SELECT + c.CustomerID, + c.CustomerName, + o.OrderID, + o.OrderDate +FROM + OPENXML(@DocHandle, '/Customers/Customer', 2) + WITH ( + CustomerID int '@ID', + CustomerName varchar(50) '@Name' + ) c +CROSS APPLY + OPENXML(@DocHandle, + concat('/Customers/Customer[@ID=', c.CustomerID, ']/Order'), + 2) + WITH ( + OrderID int '@ID', + OrderDate date '@Date' + ) o; + +EXEC sp_xml_removedocument @DocHandle; +GO + +-- cross apply for different row patterns +DECLARE @DocHandle int; +DECLARE @XmlDocument nvarchar(1000); +SET @XmlDocument = N''; +EXEC sp_xml_preparedocument @DocHandle OUTPUT, @XmlDocument; +SELECT + c.CustomerID, + c.CustomerName, + o.OrderID, + o.OrderDate +FROM + OPENXML(@DocHandle, '/Customers/Customer', 2) + WITH ( + CustomerID int '@ID', + CustomerName varchar(50) '@Name' + ) c +CROSS APPLY + OPENXML(@DocHandle, + concat('/Customers/Customer[@ID=', c.CustomerID, ']/Order'), + 2) + WITH ( + OrderID int '@ID', + OrderDate date '@Date' + ) o; +EXEC sp_xml_removedocument @DocHandle; +GO + +-- Basic CROSS APPLY with OPENXML using table reference +INSERT INTO person_table VALUES (1, 'John', 25), (2, 'Jane', 30); + +DECLARE @xml_doc INT; +EXEC sp_xml_preparedocument @xml_doc OUTPUT, ''; + +SELECT * FROM +(SELECT 1 as id) t +CROSS APPLY OPENXML(@xml_doc, '/root/person') WITH person_table; + +EXEC sp_xml_removedocument @xml_doc; +GO + +-- OUTER APPLY +DECLARE @xml_doc2 INT; +EXEC sp_xml_preparedocument @xml_doc2 OUTPUT, +' + + + + + +'; + +SELECT + c.customer_id, + c.customer_name, + o.order_id, + o.amount +FROM + OPENXML(@xml_doc2, '/data/customer', 1) WITH ( + customer_id INT, + customer_name VARCHAR(50) + ) c +OUTER APPLY + OPENXML(@xml_doc2, '/data/order', 1) WITH ( + cust_id INT, + order_id INT, + amount DECIMAL(10,2) + ) o; + +EXEC sp_xml_removedocument @xml_doc2; +GO + +-- Base table with outer apply openxml +INSERT INTO regions VALUES (1, 'North'), (2, 'South'), (3, 'East'), (4, 'West'); + +DECLARE @xml_doc3 INT; +EXEC sp_xml_preparedocument @xml_doc3 OUTPUT, +' + + + + + + + +'; + +SELECT + r.region_id, + r.region_name, + s.amount, + s.product +FROM + regions r +OUTER APPLY + OPENXML(@xml_doc3, '/sales/region/sale', 2) WITH ( + region_id INT '../@id', + amount DECIMAL(10,2), + product VARCHAR(50) + ) s +WHERE s.region_id = r.region_id OR s.region_id IS NULL; + +EXEC sp_xml_removedocument @xml_doc3; +GO + +-- With namespaces +--test1 +DECLARE @xml nvarchar(1000) = +' + value1 + value2 +'; +DECLARE @namespace nvarchar(100) = ''; +DECLARE @handle INT; +EXEC sp_xml_preparedocument @handle OUTPUT, @xml, @namespace; +SELECT * FROM OPENXML(@handle, '/root/ns1:child', 3) WITH (child nvarchar(10) '.'); +EXEC sp_xml_removedocument @handle; +GO + +DECLARE @h int; +EXEC sp_xml_preparedocument @h OUTPUT, + N' + + TaU + + ', + ''; + +SELECT * FROM openxml(@h, '/root/b:Elem', 3) + WITH (Col1 varchar(20) '.'); +EXEC sp_xml_removedocument @h; +GO + +-- test2 +DECLARE @xml nvarchar(2000) = ' + + + John Doe + 50000 + + + Jane Smith + 60000 + +'; + +DECLARE @namespace nvarchar(200) = ' +'; + +DECLARE @handle INT; +EXEC sp_xml_preparedocument @handle OUTPUT, @xml, @namespace; + +SELECT * FROM OPENXML(@handle, '/root/hr:employee', 2) +WITH ( + name nvarchar(50) 'hr:name', + salary int 'fin:salary', + currency nvarchar(10) 'fin:salary/@currency' +); + +EXEC sp_xml_removedocument @handle; +GO + +--test3 +DECLARE @xml nvarchar(2000) = ' + + + + Laptop + 999.99 + + + Smartphone + 599.99 + + +'; + +DECLARE @namespace nvarchar(200) = ' +'; + +DECLARE @handle INT; +EXEC sp_xml_preparedocument @handle OUTPUT, @xml, @namespace; + +SELECT * FROM OPENXML(@handle, '/catalog/cat:category/prod:product', 2) +WITH ( + category_name nvarchar(50) '../../@name', + product_name nvarchar(50) 'prod:name', + price decimal(10,2) 'prod:price' +); + +EXEC sp_xml_removedocument @handle; +GO + +--test4 +DECLARE @xml nvarchar(2000) = ' + + + + Alice Johnson + alice@email.com + + + Widget A + Widget B + + +'; + +DECLARE @namespace nvarchar(200) = ' +'; + +DECLARE @handle INT; +EXEC sp_xml_preparedocument @handle OUTPUT, @xml, @namespace; + +SELECT * FROM OPENXML(@handle, '/orders/ord:order/prod:items/prod:item', 2) +WITH ( + order_id int '../../../@id', + customer_name nvarchar(50) '../../../cust:customer/cust:name', + item_name nvarchar(50) '.', + quantity int '@qty' +); + +EXEC sp_xml_removedocument @handle; +GO + +--test5 +DECLARE @xml nvarchar(2000) = ' + + + New York + + 20 + 65 + + +'; + +DECLARE @namespace nvarchar(200) = ' +'; + +DECLARE @handle INT; +EXEC sp_xml_preparedocument @handle OUTPUT, @xml, @namespace; + +SELECT * FROM OPENXML(@handle, '/weather/loc:city', 2) +WITH ( + city_id varchar(10) '@id', + city_name varchar(50) 'loc:name', + temperature int 'met:conditions/met:temperature', + temp_unit varchar(1) 'met:conditions/met:temperature/@unit', + humidity int 'met:conditions/met:humidity', + reading_date date 'met:conditions/@date' +); + +EXEC sp_xml_removedocument @handle; +GO + +--test6 +DECLARE @xml nvarchar(2000) = ' + + + + John Smith + 45 + + + Dr. Brown + Cardiology + + + Hypertension + Lisinopril + + +'; + +DECLARE @namespace nvarchar(200) = ' +'; + +DECLARE @handle INT; +EXEC sp_xml_preparedocument @handle OUTPUT, @xml, @namespace; + +SELECT * FROM OPENXML(@handle, '/medical/pat:record', 2) +WITH ( + record_id int '@id', + patient_name nvarchar(50) 'pat:info/pat:name', + patient_age int 'pat:info/pat:age', + doctor_name nvarchar(50) 'doc:physician/doc:name', + specialty nvarchar(50) 'doc:physician/doc:specialty', + diagnosis nvarchar(100) 'treat:treatment/treat:diagnosis', + medication nvarchar(100) 'treat:treatment/treat:medication' +); + +EXEC sp_xml_removedocument @handle; +GO + +--test7 +DECLARE @xml nvarchar(2000) = ' + + + John Doe + 50000 + + + Jane Smith + 60000 + +'; + +DECLARE @namespace nvarchar(200) = ' +'; + +DECLARE @handle INT; +EXEC sp_xml_preparedocument @handle OUTPUT, @xml, @namespace; + +SELECT * FROM OPENXML(@handle, '/employees/hr:employee', 1) +WITH ( + id int, + department varchar(20), + name varchar(50), + salary int +); + +SELECT * FROM OPENXML(@handle, '/employees/hr:employee', 2) +WITH ( + id int, + department varchar(20), + name varchar(50), + salary int +); + +EXEC sp_xml_removedocument @handle; +GO + +--test8 +DECLARE @xml nvarchar(2000) = ' + + + John Doe + 50000 + + + Jane Smith + 60000 + +'; + +DECLARE @namespace nvarchar(200) = ' +'; + +DECLARE @handle INT; +EXEC sp_xml_preparedocument @handle OUTPUT, @xml, @namespace; + +SELECT * FROM OPENXML(@handle, '/employees/hr:employee', 3) +WITH ( + id int '@id', + department varchar(20) '@department', + name varchar(50) 'hr:name', + salary int 'hr:salary' +); + +EXEC sp_xml_removedocument @handle; +GO + +--test9 +DECLARE @xml nvarchar(2000) = ' + + + + + + + +'; + +DECLARE @namespace nvarchar(200) = ' +'; + +DECLARE @handle INT; +EXEC sp_xml_preparedocument @handle OUTPUT, @xml, @namespace; + +SELECT * FROM OPENXML(@handle, '/root/cust:Customer', 1) +WITH ( + customerid varchar(10), + contactname varchar(50), + country varchar(20) +); + +EXEC sp_xml_removedocument @handle; +GO + +--test10 +DECLARE @xml nvarchar(2000) = ' + + + 1001 + John + Doe + IT + + + 1002 + Jane + Smith + HR + +'; + +DECLARE @namespace nvarchar(200) = ' +'; + +DECLARE @handle INT; +EXEC sp_xml_preparedocument @handle OUTPUT, @xml, @namespace; + +SELECT * FROM OPENXML(@handle, '/root/emp:Employee', 2) +WITH ( + EmployeeId varchar(10), + FirstName varchar(50), + LastName varchar(50), + Department varchar(20) +); + +EXEC sp_xml_removedocument @handle; +GO + +--test11 +DECLARE @xml nvarchar(2000) = ' + + + John Doe + 100.00 + + + Jane Smith + 200.00 + +'; + +DECLARE @namespace nvarchar(200) = ' +'; + +DECLARE @handle INT; +EXEC sp_xml_preparedocument @handle OUTPUT, @xml, @namespace; + +SELECT * FROM OPENXML(@handle, '/root/ord:Order', 3) +WITH ( + id varchar(10), + date datetime, + CustomerName varchar(50), + Total decimal(10,2) +); + +EXEC sp_xml_removedocument @handle; +GO + +--test12 +DECLARE @xml nvarchar(2000) = ' + + + John Doe + + 123 Main St + New York + + + + Jane Smith + + 456 Oak Ave + Los Angeles + + +'; + +DECLARE @namespace nvarchar(200) = ' +'; + +DECLARE @handle INT; +EXEC sp_xml_preparedocument @handle OUTPUT, @xml, @namespace; + +SELECT * FROM OPENXML(@handle, '/root/cust:Customer', 3) +WITH ( + id varchar(10), + Name varchar(50), + Street varchar(100), + City varchar(50) +); + +EXEC sp_xml_removedocument @handle; +GO + +--test13 +DECLARE @xml nvarchar(2000) = ' + + + + 1000.00 + 100.00 + 1100.00 + + + + + 2000.00 + 200.00 + 2200.00 + + +'; + +DECLARE @namespace nvarchar(200) = ' +'; + +DECLARE @handle INT; +EXEC sp_xml_preparedocument @handle OUTPUT, @xml, @namespace; + +SELECT * FROM OPENXML(@handle, '/root/inv:Invoice', 3) +WITH ( + number varchar(10), + type varchar(20), + Amount decimal(10,2), + Tax decimal(10,2), + Total decimal(10,2) +); + +EXEC sp_xml_removedocument @handle; +GO + +-- Tests for tsql_openxml_get_colpattern and tsql_openxml_get_xmldoc +-- Test basic flag patterns +SELECT sys.tsql_openxml_get_colpattern('name', 0); +GO + +SELECT sys.tsql_openxml_get_colpattern('name', 1); +GO + +SELECT sys.tsql_openxml_get_colpattern('name', 2); +GO + +SELECT sys.tsql_openxml_get_colpattern('name', 3); +GO + +-- Test flag normalization (mod 4) +SELECT sys.tsql_openxml_get_colpattern('id', 4) +GO + +SELECT sys.tsql_openxml_get_colpattern('id', 5); +GO + +SELECT sys.tsql_openxml_get_colpattern('id', 6); +GO + +SELECT sys.tsql_openxml_get_colpattern('id', 7); +GO + +-- Test error and null cases +SELECT sys.tsql_openxml_get_colpattern(NULL, 1); +GO + +SELECT sys.tsql_openxml_get_colpattern('', 1); +GO + +SELECT sys.tsql_openxml_get_colpattern('name', -1); +GO + +-- Test with valid document handle +DECLARE @doc_handle INT; +EXEC sp_xml_preparedocument @doc_handle OUTPUT, 'test'; +SELECT sys.tsql_openxml_get_xmldoc(@doc_handle); +EXEC sp_xml_removedocument @doc_handle; +GO + +-- Test with invalid or NULL handle +SELECT sys.tsql_openxml_get_xmldoc(999); +GO +SELECT sys.tsql_openxml_get_xmldoc(NULL); +GO + +-- Tests for views for col pattern and xml doc generation +SELECT * FROM openxml_column_patterns WHERE flag = 3; +GO + +SELECT document_id FROM openxml_documents; +GO \ No newline at end of file diff --git a/test/JDBC/upgrade/13_4/schedule b/test/JDBC/upgrade/13_4/schedule index 67c5ccd30ea..96d4c94e90f 100644 --- a/test/JDBC/upgrade/13_4/schedule +++ b/test/JDBC/upgrade/13_4/schedule @@ -262,7 +262,7 @@ BABEL-5031 test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument -openxml_with_clause +openxml_with_clause-before-17_7 fixeddecimal_modulo BABEL-NUMERIC_EXPR test_conv_float_to_varchar_char_before_17_4 diff --git a/test/JDBC/upgrade/13_5/schedule b/test/JDBC/upgrade/13_5/schedule index 7204c19331f..374e464a5b9 100644 --- a/test/JDBC/upgrade/13_5/schedule +++ b/test/JDBC/upgrade/13_5/schedule @@ -315,7 +315,7 @@ BABEL-5031 test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument -openxml_with_clause +openxml_with_clause-before-17_7 fixeddecimal_modulo BABEL-NUMERIC_EXPR test_conv_float_to_varchar_char_before_17_4 diff --git a/test/JDBC/upgrade/13_6/schedule b/test/JDBC/upgrade/13_6/schedule index a32ed96b733..5f0c3fbbc85 100644 --- a/test/JDBC/upgrade/13_6/schedule +++ b/test/JDBC/upgrade/13_6/schedule @@ -373,7 +373,7 @@ BABEL-USER-GRANT test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument -openxml_with_clause +openxml_with_clause-before-17_7 fixeddecimal_modulo BABEL-NUMERIC_EXPR test_conv_float_to_varchar_char_before_17_4 diff --git a/test/JDBC/upgrade/13_7/schedule b/test/JDBC/upgrade/13_7/schedule index b71da542caf..53c1b54568e 100644 --- a/test/JDBC/upgrade/13_7/schedule +++ b/test/JDBC/upgrade/13_7/schedule @@ -366,7 +366,7 @@ BABEL-USER-GRANT test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument -openxml_with_clause +openxml_with_clause-before-17_7 fixeddecimal_modulo BABEL-NUMERIC_EXPR test_conv_float_to_varchar_char_before_17_4 diff --git a/test/JDBC/upgrade/13_8/schedule b/test/JDBC/upgrade/13_8/schedule index b71da542caf..53c1b54568e 100644 --- a/test/JDBC/upgrade/13_8/schedule +++ b/test/JDBC/upgrade/13_8/schedule @@ -366,7 +366,7 @@ BABEL-USER-GRANT test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument -openxml_with_clause +openxml_with_clause-before-17_7 fixeddecimal_modulo BABEL-NUMERIC_EXPR test_conv_float_to_varchar_char_before_17_4 diff --git a/test/JDBC/upgrade/13_9/schedule b/test/JDBC/upgrade/13_9/schedule index 2bea664a0d1..6c802de2e16 100644 --- a/test/JDBC/upgrade/13_9/schedule +++ b/test/JDBC/upgrade/13_9/schedule @@ -371,7 +371,7 @@ BABEL-USER-GRANT test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument -openxml_with_clause +openxml_with_clause-before-17_7 fixeddecimal_modulo BABEL-NUMERIC_EXPR test_conv_float_to_varchar_char_before_17_4 diff --git a/test/JDBC/upgrade/14_10/schedule b/test/JDBC/upgrade/14_10/schedule index ef53442598e..e9e94980ae1 100644 --- a/test/JDBC/upgrade/14_10/schedule +++ b/test/JDBC/upgrade/14_10/schedule @@ -484,7 +484,7 @@ BABEL-USER-GRANT test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument -openxml_with_clause +openxml_with_clause-before-17_7 fixeddecimal_modulo BABEL-NUMERIC_EXPR BABEL-5467 diff --git a/test/JDBC/upgrade/14_11/schedule b/test/JDBC/upgrade/14_11/schedule index dabbfb5d8fa..016c70619de 100644 --- a/test/JDBC/upgrade/14_11/schedule +++ b/test/JDBC/upgrade/14_11/schedule @@ -482,7 +482,7 @@ BABEL-USER-GRANT test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument -openxml_with_clause +openxml_with_clause-before-17_7 fixeddecimal_modulo BABEL-NUMERIC_EXPR BABEL-5467 diff --git a/test/JDBC/upgrade/14_12/schedule b/test/JDBC/upgrade/14_12/schedule index 61dcd1b14b2..72ae46b7ee2 100644 --- a/test/JDBC/upgrade/14_12/schedule +++ b/test/JDBC/upgrade/14_12/schedule @@ -483,7 +483,7 @@ BABEL-USER-GRANT test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument -openxml_with_clause +openxml_with_clause-before-17_7 fixeddecimal_modulo BABEL-NUMERIC_EXPR BABEL-5467 diff --git a/test/JDBC/upgrade/14_13/schedule b/test/JDBC/upgrade/14_13/schedule index ab534161ccc..5b9a0e72793 100644 --- a/test/JDBC/upgrade/14_13/schedule +++ b/test/JDBC/upgrade/14_13/schedule @@ -483,7 +483,7 @@ BABEL-USER-GRANT test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument -openxml_with_clause +openxml_with_clause-before-17_7 fixeddecimal_modulo BABEL-NUMERIC_EXPR BABEL-5467 diff --git a/test/JDBC/upgrade/14_15/schedule b/test/JDBC/upgrade/14_15/schedule index 5e3ce6bf1c3..5b96d92141b 100644 --- a/test/JDBC/upgrade/14_15/schedule +++ b/test/JDBC/upgrade/14_15/schedule @@ -479,7 +479,7 @@ BABEL-USER-GRANT test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument -openxml_with_clause +openxml_with_clause-before-17_7 fixeddecimal_modulo BABEL-NUMERIC_EXPR test_conv_float_to_varchar_char_before_17_4 diff --git a/test/JDBC/upgrade/14_18/schedule b/test/JDBC/upgrade/14_18/schedule index 27a66aa811a..be36e06b59f 100644 --- a/test/JDBC/upgrade/14_18/schedule +++ b/test/JDBC/upgrade/14_18/schedule @@ -479,7 +479,7 @@ BABEL-USER-GRANT test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument -openxml_with_clause +openxml_with_clause-before-17_7 fixeddecimal_modulo BABEL-NUMERIC_EXPR BABEL-5467 diff --git a/test/JDBC/upgrade/14_3/schedule b/test/JDBC/upgrade/14_3/schedule index a42c07d51f9..601aaefbc60 100644 --- a/test/JDBC/upgrade/14_3/schedule +++ b/test/JDBC/upgrade/14_3/schedule @@ -402,7 +402,7 @@ BABEL-USER-GRANT test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument -openxml_with_clause +openxml_with_clause-before-17_7 fixeddecimal_modulo BABEL-NUMERIC_EXPR BABEL-5467 diff --git a/test/JDBC/upgrade/14_5/schedule b/test/JDBC/upgrade/14_5/schedule index 7d3bc2b4960..50b1125a504 100644 --- a/test/JDBC/upgrade/14_5/schedule +++ b/test/JDBC/upgrade/14_5/schedule @@ -414,7 +414,7 @@ BABEL-USER-GRANT test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument -openxml_with_clause +openxml_with_clause-before-17_7 fixeddecimal_modulo BABEL-NUMERIC_EXPR BABEL-5467 diff --git a/test/JDBC/upgrade/14_6/schedule b/test/JDBC/upgrade/14_6/schedule index 6ad23485103..58b0e94ced2 100644 --- a/test/JDBC/upgrade/14_6/schedule +++ b/test/JDBC/upgrade/14_6/schedule @@ -452,7 +452,7 @@ BABEL-USER-GRANT test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument -openxml_with_clause +openxml_with_clause-before-17_7 fixeddecimal_modulo BABEL-NUMERIC_EXPR BABEL-5467 diff --git a/test/JDBC/upgrade/14_7/schedule b/test/JDBC/upgrade/14_7/schedule index 8709baac27a..ff29755e123 100644 --- a/test/JDBC/upgrade/14_7/schedule +++ b/test/JDBC/upgrade/14_7/schedule @@ -474,7 +474,7 @@ BABEL-USER-GRANT test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument -openxml_with_clause +openxml_with_clause-before-17_7 fixeddecimal_modulo BABEL-NUMERIC_EXPR BABEL-5467 diff --git a/test/JDBC/upgrade/14_8/schedule b/test/JDBC/upgrade/14_8/schedule index bf361cdca3a..13e1af747ca 100644 --- a/test/JDBC/upgrade/14_8/schedule +++ b/test/JDBC/upgrade/14_8/schedule @@ -476,7 +476,7 @@ BABEL-USER-GRANT test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument -openxml_with_clause +openxml_with_clause-before-17_7 fixeddecimal_modulo BABEL-NUMERIC_EXPR BABEL-5467 diff --git a/test/JDBC/upgrade/14_9/schedule b/test/JDBC/upgrade/14_9/schedule index 3f219872a8e..4cfb2827ff4 100644 --- a/test/JDBC/upgrade/14_9/schedule +++ b/test/JDBC/upgrade/14_9/schedule @@ -479,7 +479,7 @@ BABEL-USER-GRANT test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument -openxml_with_clause +openxml_with_clause-before-17_7 fixeddecimal_modulo BABEL-NUMERIC_EXPR BABEL-5467 diff --git a/test/JDBC/upgrade/15_1/schedule b/test/JDBC/upgrade/15_1/schedule index a7dc2521227..ee08eb421e6 100644 --- a/test/JDBC/upgrade/15_1/schedule +++ b/test/JDBC/upgrade/15_1/schedule @@ -452,7 +452,7 @@ BABEL-USER-GRANT test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument -openxml_with_clause +openxml_with_clause-before-17_7 fixeddecimal_modulo BABEL-NUMERIC_EXPR BABEL-5467 diff --git a/test/JDBC/upgrade/15_10/schedule b/test/JDBC/upgrade/15_10/schedule index 31a64f1803d..09d7d835ef1 100644 --- a/test/JDBC/upgrade/15_10/schedule +++ b/test/JDBC/upgrade/15_10/schedule @@ -570,7 +570,7 @@ BABEL-USER-GRANT test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument -openxml_with_clause +openxml_with_clause-before-17_7 fixeddecimal_modulo BABEL-NUMERIC_EXPR BABEL-5467 diff --git a/test/JDBC/upgrade/15_12/schedule b/test/JDBC/upgrade/15_12/schedule index 21f618a3a3c..04eecf3c119 100644 --- a/test/JDBC/upgrade/15_12/schedule +++ b/test/JDBC/upgrade/15_12/schedule @@ -570,7 +570,7 @@ BABEL-USER-GRANT test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument -openxml_with_clause +openxml_with_clause-before-17_7 fixeddecimal_modulo BABEL-NUMERIC_EXPR BABEL-5467 diff --git a/test/JDBC/upgrade/15_13/schedule b/test/JDBC/upgrade/15_13/schedule index 761e4c6b493..d83c3c6ddf2 100644 --- a/test/JDBC/upgrade/15_13/schedule +++ b/test/JDBC/upgrade/15_13/schedule @@ -570,7 +570,7 @@ BABEL-USER-GRANT test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument -openxml_with_clause +openxml_with_clause-before-17_7 fixeddecimal_modulo BABEL-NUMERIC_EXPR BABEL-5467 diff --git a/test/JDBC/upgrade/15_14/schedule b/test/JDBC/upgrade/15_14/schedule index 586fb408f24..1c976c16a68 100644 --- a/test/JDBC/upgrade/15_14/schedule +++ b/test/JDBC/upgrade/15_14/schedule @@ -570,7 +570,7 @@ BABEL-USER-GRANT test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument -openxml_with_clause +openxml_with_clause-before-17_7 fixeddecimal_modulo BABEL-NUMERIC_EXPR BABEL-5467 diff --git a/test/JDBC/upgrade/15_15/schedule b/test/JDBC/upgrade/15_15/schedule index 1b3b5d724de..61595f0e749 100644 --- a/test/JDBC/upgrade/15_15/schedule +++ b/test/JDBC/upgrade/15_15/schedule @@ -568,7 +568,7 @@ test_conv_string_to_time-before-17_4 BABEL-5031 BABEL-USER-GRANT test_conv_money_to_varchar -openxml_with_clause +openxml_with_clause-before-17_7 fixeddecimal_modulo BABEL-NUMERIC_EXPR BABEL-5467 diff --git a/test/JDBC/upgrade/15_2/schedule b/test/JDBC/upgrade/15_2/schedule index 76f44264b45..d44375b1d24 100644 --- a/test/JDBC/upgrade/15_2/schedule +++ b/test/JDBC/upgrade/15_2/schedule @@ -488,7 +488,7 @@ BABEL-USER-GRANT test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument -openxml_with_clause +openxml_with_clause-before-17_7 fixeddecimal_modulo BABEL-NUMERIC_EXPR BABEL-5467 diff --git a/test/JDBC/upgrade/15_3/schedule b/test/JDBC/upgrade/15_3/schedule index 8d7172e3bf1..71fe68b6344 100644 --- a/test/JDBC/upgrade/15_3/schedule +++ b/test/JDBC/upgrade/15_3/schedule @@ -508,7 +508,7 @@ BABEL-USER-GRANT test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument -openxml_with_clause +openxml_with_clause-before-17_7 fixeddecimal_modulo BABEL-NUMERIC_EXPR BABEL-5467 diff --git a/test/JDBC/upgrade/15_4/schedule b/test/JDBC/upgrade/15_4/schedule index b9b10720d22..8979cdacfff 100644 --- a/test/JDBC/upgrade/15_4/schedule +++ b/test/JDBC/upgrade/15_4/schedule @@ -521,7 +521,7 @@ BABEL-USER-GRANT test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument -openxml_with_clause +openxml_with_clause-before-17_7 fixeddecimal_modulo BABEL-NUMERIC_EXPR BABEL-5467 diff --git a/test/JDBC/upgrade/15_5/schedule b/test/JDBC/upgrade/15_5/schedule index f9ac8953f7e..43d801a420b 100644 --- a/test/JDBC/upgrade/15_5/schedule +++ b/test/JDBC/upgrade/15_5/schedule @@ -555,7 +555,7 @@ BABEL-USER-GRANT test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument -openxml_with_clause +openxml_with_clause-before-17_7 fixeddecimal_modulo BABEL-NUMERIC_EXPR test_conv_float_to_varchar_char_before_17_4 diff --git a/test/JDBC/upgrade/15_6/schedule b/test/JDBC/upgrade/15_6/schedule index 5eee4ef1402..a24cb9edc56 100644 --- a/test/JDBC/upgrade/15_6/schedule +++ b/test/JDBC/upgrade/15_6/schedule @@ -570,7 +570,7 @@ BABEL-USER-GRANT test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument -openxml_with_clause +openxml_with_clause-before-17_7 fixeddecimal_modulo BABEL-NUMERIC_EXPR BABEL-5467 diff --git a/test/JDBC/upgrade/15_7/schedule b/test/JDBC/upgrade/15_7/schedule index 6525fad581b..53249c1037e 100644 --- a/test/JDBC/upgrade/15_7/schedule +++ b/test/JDBC/upgrade/15_7/schedule @@ -578,7 +578,7 @@ BABEL-USER-GRANT test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument -openxml_with_clause +openxml_with_clause-before-17_7 fixeddecimal_modulo BABEL-NUMERIC_EXPR BABEL-5467 diff --git a/test/JDBC/upgrade/15_8/schedule b/test/JDBC/upgrade/15_8/schedule index 4f9f245aa96..94f4be2f839 100644 --- a/test/JDBC/upgrade/15_8/schedule +++ b/test/JDBC/upgrade/15_8/schedule @@ -570,7 +570,7 @@ BABEL-USER-GRANT test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument -openxml_with_clause +openxml_with_clause-before-17_7 fixeddecimal_modulo BABEL-NUMERIC_EXPR BABEL-5467 diff --git a/test/JDBC/upgrade/16_1/schedule b/test/JDBC/upgrade/16_1/schedule index 4e3375a47ce..3c472be7b56 100644 --- a/test/JDBC/upgrade/16_1/schedule +++ b/test/JDBC/upgrade/16_1/schedule @@ -563,7 +563,7 @@ BABEL-USER-GRANT test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument -openxml_with_clause +openxml_with_clause-before-17_7 fixeddecimal_modulo BABEL-NUMERIC_EXPR test_conv_float_to_varchar_char_before_17_4 diff --git a/test/JDBC/upgrade/16_10/schedule b/test/JDBC/upgrade/16_10/schedule index 68fa04398e9..60ea3608323 100644 --- a/test/JDBC/upgrade/16_10/schedule +++ b/test/JDBC/upgrade/16_10/schedule @@ -605,7 +605,7 @@ BABEL-USER-GRANT test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument -openxml_with_clause +openxml_with_clause-before-17_7 fixeddecimal_modulo BABEL-NUMERIC_EXPR test_conv_float_to_varchar_char diff --git a/test/JDBC/upgrade/16_11/schedule b/test/JDBC/upgrade/16_11/schedule index 566e971d5f2..d9fb6ba07e6 100644 --- a/test/JDBC/upgrade/16_11/schedule +++ b/test/JDBC/upgrade/16_11/schedule @@ -605,7 +605,7 @@ BABEL-USER-GRANT test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument -openxml_with_clause +openxml_with_clause-before-17_7 fixeddecimal_modulo BABEL-NUMERIC_EXPR test_conv_float_to_varchar_char diff --git a/test/JDBC/upgrade/16_2/schedule b/test/JDBC/upgrade/16_2/schedule index 12f52440eb3..4d0454992a8 100644 --- a/test/JDBC/upgrade/16_2/schedule +++ b/test/JDBC/upgrade/16_2/schedule @@ -579,7 +579,7 @@ BABEL-USER-GRANT test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument -openxml_with_clause +openxml_with_clause-before-17_7 fixeddecimal_modulo BABEL-NUMERIC_EXPR test_conv_float_to_varchar_char_before_17_4 diff --git a/test/JDBC/upgrade/16_3/schedule b/test/JDBC/upgrade/16_3/schedule index 183ea8371e2..e687dee3f79 100644 --- a/test/JDBC/upgrade/16_3/schedule +++ b/test/JDBC/upgrade/16_3/schedule @@ -582,7 +582,7 @@ BABEL-USER-GRANT test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument -openxml_with_clause +openxml_with_clause-before-17_7 fixeddecimal_modulo BABEL-NUMERIC_EXPR test_conv_float_to_varchar_char_before_17_4 diff --git a/test/JDBC/upgrade/16_4/schedule b/test/JDBC/upgrade/16_4/schedule index f3b86db8176..8ce7b327d98 100644 --- a/test/JDBC/upgrade/16_4/schedule +++ b/test/JDBC/upgrade/16_4/schedule @@ -596,7 +596,7 @@ BABEL-USER-GRANT test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument -openxml_with_clause +openxml_with_clause-before-17_7 fixeddecimal_modulo BABEL-NUMERIC_EXPR test_conv_float_to_varchar_char_before_17_4 diff --git a/test/JDBC/upgrade/16_6/schedule b/test/JDBC/upgrade/16_6/schedule index 27dced8c50d..f24fffbe8cb 100644 --- a/test/JDBC/upgrade/16_6/schedule +++ b/test/JDBC/upgrade/16_6/schedule @@ -599,7 +599,7 @@ BABEL-USER-GRANT test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument -openxml_with_clause +openxml_with_clause-before-17_7 fixeddecimal_modulo BABEL-NUMERIC_EXPR test_conv_float_to_varchar_char_before_17_4 diff --git a/test/JDBC/upgrade/16_8/schedule b/test/JDBC/upgrade/16_8/schedule index c448a705e26..f623b7fda45 100644 --- a/test/JDBC/upgrade/16_8/schedule +++ b/test/JDBC/upgrade/16_8/schedule @@ -604,7 +604,7 @@ BABEL-USER-GRANT test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument -openxml_with_clause +openxml_with_clause-before-17_7 fixeddecimal_modulo BABEL-NUMERIC_EXPR test_conv_float_to_varchar_char diff --git a/test/JDBC/upgrade/16_9/schedule b/test/JDBC/upgrade/16_9/schedule index 6d0c4548fbd..e4a7dc70d4e 100644 --- a/test/JDBC/upgrade/16_9/schedule +++ b/test/JDBC/upgrade/16_9/schedule @@ -606,7 +606,7 @@ BABEL-USER-GRANT test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument -openxml_with_clause +openxml_with_clause-before-17_7 fixeddecimal_modulo BABEL-NUMERIC_EXPR test_conv_float_to_varchar_char diff --git a/test/JDBC/upgrade/17_4/schedule b/test/JDBC/upgrade/17_4/schedule index 16f3d67997d..3ec0007442f 100644 --- a/test/JDBC/upgrade/17_4/schedule +++ b/test/JDBC/upgrade/17_4/schedule @@ -601,7 +601,7 @@ BABEL-USER-GRANT test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument -openxml_with_clause +openxml_with_clause-before-17_7 fixeddecimal_modulo BABEL-NUMERIC_EXPR test_conv_float_to_varchar_char diff --git a/test/JDBC/upgrade/17_5/schedule b/test/JDBC/upgrade/17_5/schedule index 7e213d160fb..1918c954954 100644 --- a/test/JDBC/upgrade/17_5/schedule +++ b/test/JDBC/upgrade/17_5/schedule @@ -606,7 +606,7 @@ BABEL-USER-GRANT test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument -openxml_with_clause +openxml_with_clause-before-17_7 fixeddecimal_modulo BABEL-NUMERIC_EXPR test_conv_float_to_varchar_char diff --git a/test/JDBC/upgrade/17_6/schedule b/test/JDBC/upgrade/17_6/schedule index cc16edcf3a8..57a3657a6cf 100644 --- a/test/JDBC/upgrade/17_6/schedule +++ b/test/JDBC/upgrade/17_6/schedule @@ -610,7 +610,7 @@ BABEL-USER-GRANT test_conv_money_to_varchar sp_xml_preparedocument sp_xml_removedocument -openxml_with_clause +openxml_with_clause-before-17_7 fixeddecimal_modulo BABEL-NUMERIC_EXPR test_conv_float_to_varchar_char diff --git a/test/python/expected/sql_validation_framework/expected_create.out b/test/python/expected/sql_validation_framework/expected_create.out index a0af69aa188..015357a3a18 100644 --- a/test/python/expected/sql_validation_framework/expected_create.out +++ b/test/python/expected/sql_validation_framework/expected_create.out @@ -56,8 +56,6 @@ Could not find tests for function sys.suser_name_internal Could not find tests for function sys.systypes_precision_helper Could not find tests for function sys.timezone Could not find tests for function sys.tsql_get_returntypmodvalue -Could not find tests for function sys.tsql_openxml_get_colpattern -Could not find tests for function sys.tsql_openxml_get_xmldoc Could not find tests for function sys.tsql_query_to_json_ffunc Could not find tests for function sys.tsql_query_to_json_sfunc Could not find tests for function sys.tsql_query_to_xml_ffunc @@ -169,8 +167,6 @@ Could not find upgrade tests for function sys.systypes_precision_helper Could not find upgrade tests for function sys.timezone Could not find upgrade tests for function sys.tsql_get_functiondef Could not find upgrade tests for function sys.tsql_get_returntypmodvalue -Could not find upgrade tests for function sys.tsql_openxml_get_colpattern -Could not find upgrade tests for function sys.tsql_openxml_get_xmldoc Could not find upgrade tests for function sys.tsql_query_to_json_ffunc Could not find upgrade tests for function sys.tsql_query_to_json_sfunc Could not find upgrade tests for function sys.tsql_query_to_xml_ffunc From eb0a5aa798568ac459fec6e47c39a549d01327ef Mon Sep 17 00:00:00 2001 From: Harsh Dubey Date: Wed, 24 Sep 2025 05:10:07 +0000 Subject: [PATCH 38/40] Fixing failures Signed-off-by: Harsh Dubey --- test/JDBC/jdbc_schedule | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/JDBC/jdbc_schedule b/test/JDBC/jdbc_schedule index 72be00186f8..476f21e7f83 100644 --- a/test/JDBC/jdbc_schedule +++ b/test/JDBC/jdbc_schedule @@ -639,6 +639,9 @@ ignore#!#view_sec_setting_before_17_6-or-16_10-vu-cleanup ignore#!#mathematical_func-before_17_7-or-16_11-vu-prepare ignore#!#mathematical_func-before_17_7-or-16_11-vu-verify ignore#!#mathematical_func-before_17_7-or-16_11-vu-cleanup +ignore#!#openxml_with_clause-before-17_7-vu-prepare +ignore#!#openxml_with_clause-before-17_7-vu-verify +ignore#!#openxml_with_clause-before-17_7-vu-cleanup ignore#!#ascii_function_before-17_7-or-16_11-vu-prepare ignore#!#ascii_function_before-17_7-or-16_11-vu-verify ignore#!#ascii_function_before-17_7-or-16_11-vu-cleanup From 40060c0217618a3828c76c231075d0cc35ad3123 Mon Sep 17 00:00:00 2001 From: Harsh Dubey Date: Wed, 24 Sep 2025 09:15:08 +0000 Subject: [PATCH 39/40] Defined the functions as extern in pltsql.h Signed-off-by: Harsh Dubey --- contrib/babelfishpg_tsql/runtime/functions.c | 2 -- contrib/babelfishpg_tsql/src/hooks.c | 2 -- contrib/babelfishpg_tsql/src/pltsql.h | 3 +++ contrib/babelfishpg_tsql/src/procedures.c | 1 - 4 files changed, 3 insertions(+), 5 deletions(-) diff --git a/contrib/babelfishpg_tsql/runtime/functions.c b/contrib/babelfishpg_tsql/runtime/functions.c index d578e72d24b..18426ec9ab2 100644 --- a/contrib/babelfishpg_tsql/runtime/functions.c +++ b/contrib/babelfishpg_tsql/runtime/functions.c @@ -212,7 +212,6 @@ void *get_servername_internal(void); void *get_servicename_internal(void); void *get_language(void); void *get_host_id(void); -void extract_namespaces_from_xml(xmltype *ns_data, char ***ns_names, char ***ns_uris, int *ns_count); Datum datepart_internal(char *field , Timestamp timestamp , float8 df_tz, bool general_integer_datatype); static HTAB *load_categories_hash(const char *sourcetext, MemoryContext per_query_ctx); @@ -244,7 +243,6 @@ extern bool inited_ht_tsql_cast_info; extern bool inited_ht_tsql_datatype_precedence_info; extern PLtsql_execstate *get_outermost_tsql_estate(int *nestlevel); extern char *replace_special_chars_fts_impl(char *input_str); -extern void get_xml_data_and_namespace_data(int document_id, xmltype **xml_data, xmltype **ns_data); #ifdef USE_LIBXML HTAB *ht_xmlNode2Id = NULL; diff --git a/contrib/babelfishpg_tsql/src/hooks.c b/contrib/babelfishpg_tsql/src/hooks.c index 3c6001b4f10..6b5f16e4d35 100644 --- a/contrib/babelfishpg_tsql/src/hooks.c +++ b/contrib/babelfishpg_tsql/src/hooks.c @@ -126,8 +126,6 @@ typedef enum PltsqlInitPrivsOptions ERROR_INIT_PRIVS } PltsqlInitPrivsOptions; -extern void get_xml_data_and_namespace_data(int document_id, xmltype **xml_data, xmltype **ns_data); -extern void extract_namespaces_from_xml(xmltype *ns_data, char ***ns_names, char ***ns_uris, int *ns_count); /***************************************** * General Hooks diff --git a/contrib/babelfishpg_tsql/src/pltsql.h b/contrib/babelfishpg_tsql/src/pltsql.h index b20d086657d..e2515dc131b 100644 --- a/contrib/babelfishpg_tsql/src/pltsql.h +++ b/contrib/babelfishpg_tsql/src/pltsql.h @@ -33,6 +33,7 @@ #include "utils/portal.h" #include "utils/typcache.h" #include "tcop/utility.h" +#include "utils/xml.h" #include "dynavec.h" #include "dynastack.h" @@ -2183,6 +2184,8 @@ extern int pltsql_yyparse(void); /* functions in hooks.c */ extern char *extract_identifier(const char *start, int *last_pos); +extern void get_xml_data_and_namespace_data(int document_id, xmltype **xml_data, xmltype **ns_data); +extern void extract_namespaces_from_xml(xmltype *ns_data, char ***ns_names, char ***ns_uris, int *ns_count); /* functions in pltsql_utils.c */ extern char *gen_createfulltextindex_cmds(const char *table_name, const char *schema_name, const List *column_name, const char *index_name); diff --git a/contrib/babelfishpg_tsql/src/procedures.c b/contrib/babelfishpg_tsql/src/procedures.c index 8f099fef48b..b51d08c5ad3 100644 --- a/contrib/babelfishpg_tsql/src/procedures.c +++ b/contrib/babelfishpg_tsql/src/procedures.c @@ -132,7 +132,6 @@ int get_next_xml_handle_counter(void); void create_xml_handle_temp_table(void); void delete_xml_handle_entry(int handle); int insert_xml_handle_entry(xmltype *xml_data,xmltype *ns_data, int xml_data_length, int ns_data_length); -void get_xml_data_and_namespace_data(int document_id, xmltype **xml_data, xmltype **ns_data); /* server options and their default values for babelfish_server_options catalog insert */ char * srvOptions_optname[BBF_SERVERS_DEF_NUM_COLS - 1] = {"query timeout", "connect timeout"}; From 2c43eb0f1e6ffa92444c5e8c1008e32dee83534d Mon Sep 17 00:00:00 2001 From: Harsh Dubey Date: Wed, 24 Sep 2025 09:36:43 +0000 Subject: [PATCH 40/40] Mark the headers of functions as extern Signed-off-by: Harsh Dubey --- contrib/babelfishpg_tsql/src/hooks.h | 3 +++ contrib/babelfishpg_tsql/src/pltsql.h | 3 --- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/contrib/babelfishpg_tsql/src/hooks.h b/contrib/babelfishpg_tsql/src/hooks.h index 27368d71fbd..fa98f74e805 100644 --- a/contrib/babelfishpg_tsql/src/hooks.h +++ b/contrib/babelfishpg_tsql/src/hooks.h @@ -5,6 +5,7 @@ #include "parser/analyze.h" #include "tcop/cmdtag.h" #include "utils/pg_locale.h" +#include "utils/xml.h" extern IsExtendedCatalogHookType PrevIsExtendedCatalogHook; extern IsToastRelationHookType PrevIsToastRelationHook; @@ -41,5 +42,7 @@ extern char *update_delete_target_alias; extern bool sp_describe_first_result_set_inprogress; extern bool handle_bbf_view_binding_on_object_drop(const ObjectAddress *droppedObject, bool is_alter_view); extern bool check_view_binding_dependencies(Query *viewParse); +extern void get_xml_data_and_namespace_data(int document_id, xmltype **xml_data, xmltype **ns_data); +extern void extract_namespaces_from_xml(xmltype *ns_data, char ***ns_names, char ***ns_uris, int *ns_count); #endif diff --git a/contrib/babelfishpg_tsql/src/pltsql.h b/contrib/babelfishpg_tsql/src/pltsql.h index e2515dc131b..b20d086657d 100644 --- a/contrib/babelfishpg_tsql/src/pltsql.h +++ b/contrib/babelfishpg_tsql/src/pltsql.h @@ -33,7 +33,6 @@ #include "utils/portal.h" #include "utils/typcache.h" #include "tcop/utility.h" -#include "utils/xml.h" #include "dynavec.h" #include "dynastack.h" @@ -2184,8 +2183,6 @@ extern int pltsql_yyparse(void); /* functions in hooks.c */ extern char *extract_identifier(const char *start, int *last_pos); -extern void get_xml_data_and_namespace_data(int document_id, xmltype **xml_data, xmltype **ns_data); -extern void extract_namespaces_from_xml(xmltype *ns_data, char ***ns_names, char ***ns_uris, int *ns_count); /* functions in pltsql_utils.c */ extern char *gen_createfulltextindex_cmds(const char *table_name, const char *schema_name, const List *column_name, const char *index_name);