From 12be4f3c8120a479ee6979d628f85390ecde0ee5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A2=85=E7=A8=8B?= <517719039@qq.com> Date: Wed, 6 Nov 2024 20:40:07 +0800 Subject: [PATCH] =?UTF-8?q?GMS=5FXMLGEN=E9=AB=98=E7=BA=A7=E5=8C=85?= =?UTF-8?q?=E5=85=BC=E5=AE=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- GNUmakefile.in | 1 + build/script/aarch64_opengauss_list | 3 + .../opengauss_release_list_ubuntu_single | 3 + build/script/x86_64_opengauss_list | 3 + contrib/CMakeLists.txt | 8 +- contrib/Makefile | 2 + contrib/gms_xmlgen/CMakeLists.txt | 21 + contrib/gms_xmlgen/Makefile | 25 + contrib/gms_xmlgen/data/dummy.txt | 1 + contrib/gms_xmlgen/expected/gms_xmlgen.out | 3260 +++++++++++++++++ contrib/gms_xmlgen/gms_xmlgen--1.0.sql | 192 + contrib/gms_xmlgen/gms_xmlgen.control | 5 + contrib/gms_xmlgen/gms_xmlgen.cpp | 1381 +++++++ contrib/gms_xmlgen/gms_xmlgen.h | 77 + contrib/gms_xmlgen/sql/gms_xmlgen.sql | 1182 ++++++ src/common/backend/utils/adt/xml.cpp | 2 +- .../optimizer/commands/dropcmds.cpp | 1 + src/include/utils/xml.h | 2 +- 18 files changed, 6166 insertions(+), 3 deletions(-) create mode 100644 contrib/gms_xmlgen/CMakeLists.txt create mode 100644 contrib/gms_xmlgen/Makefile create mode 100644 contrib/gms_xmlgen/data/dummy.txt create mode 100644 contrib/gms_xmlgen/expected/gms_xmlgen.out create mode 100644 contrib/gms_xmlgen/gms_xmlgen--1.0.sql create mode 100644 contrib/gms_xmlgen/gms_xmlgen.control create mode 100644 contrib/gms_xmlgen/gms_xmlgen.cpp create mode 100644 contrib/gms_xmlgen/gms_xmlgen.h create mode 100644 contrib/gms_xmlgen/sql/gms_xmlgen.sql diff --git a/GNUmakefile.in b/GNUmakefile.in index 7b904a345..76f1c063d 100644 --- a/GNUmakefile.in +++ b/GNUmakefile.in @@ -107,6 +107,7 @@ install: @if test -d contrib/gms_stats; then $(MAKE) -C contrib/gms_stats $@; fi @if test -d contrib/gms_tcp; then $(MAKE) -C contrib/gms_tcp $@; fi @if test -d contrib/gms_profiler; then $(MAKE) -C contrib/gms_profiler $@; fi + @if test -d contrib/gms_xmlgen; then $(MAKE) -C contrib/gms_xmlgen $@; fi @if test -d contrib/gms_output; then $(MAKE) -C contrib/gms_output $@; fi @if test -d contrib/timescaledb; then (./contrib/timescaledb/run_to_build.sh && $(MAKE) -C contrib/timescaledb/build $@); fi @if test -d contrib/chparser; then \ diff --git a/build/script/aarch64_opengauss_list b/build/script/aarch64_opengauss_list index 0bbf5b388..ce787a7c0 100644 --- a/build/script/aarch64_opengauss_list +++ b/build/script/aarch64_opengauss_list @@ -133,6 +133,8 @@ ./share/postgresql/extension/gms_profiler.control ./share/postgresql/extension/gms_sql--1.0.sql ./share/postgresql/extension/gms_sql.control +./share/postgresql/extension/gms_xmlgen--1.0.sql +./share/postgresql/extension/gms_xmlgen.control ./share/postgresql/timezone/GB-Eire ./share/postgresql/timezone/Turkey ./share/postgresql/timezone/Kwajalein @@ -838,6 +840,7 @@ ./lib/postgresql/gms_tcp.so ./lib/postgresql/gms_profiler.so ./lib/postgresql/gms_sql.so +./lib/postgresql/gms_xmlgen.so ./lib/libpljava.so ./lib/libpq.a ./lib/libpq.so diff --git a/build/script/opengauss_release_list_ubuntu_single b/build/script/opengauss_release_list_ubuntu_single index 7f37aa985..9e772726a 100644 --- a/build/script/opengauss_release_list_ubuntu_single +++ b/build/script/opengauss_release_list_ubuntu_single @@ -121,6 +121,8 @@ ./share/postgresql/extension/gms_sql.control ./share/postgresql/extension/gms_tcp--1.0.sql ./share/postgresql/extension/gms_tcp.control +./share/postgresql/extension/gms_xmlgen--1.0.sql +./share/postgresql/extension/gms_xmlgen.control ./share/postgresql/timezone/GB-Eire ./share/postgresql/timezone/Turkey ./share/postgresql/timezone/Kwajalein @@ -808,6 +810,7 @@ ./lib/postgresql/gms_profiler.so ./lib/postgresql/gms_sql.so ./lib/postgresql/gms_tcp.so +./lib/postgresql/gms_xmlgen.so ./lib/libpljava.so ./lib/libpq.a ./lib/libpq.so diff --git a/build/script/x86_64_opengauss_list b/build/script/x86_64_opengauss_list index 2807efe99..e3e71c76d 100644 --- a/build/script/x86_64_opengauss_list +++ b/build/script/x86_64_opengauss_list @@ -133,6 +133,8 @@ ./share/postgresql/extension/gms_profiler.control ./share/postgresql/extension/gms_sql--1.0.sql ./share/postgresql/extension/gms_sql.control +./share/postgresql/extension/gms_xmlgen--1.0.sql +./share/postgresql/extension/gms_xmlgen.control ./share/postgresql/timezone/GB-Eire ./share/postgresql/timezone/Turkey ./share/postgresql/timezone/Kwajalein @@ -838,6 +840,7 @@ ./lib/postgresql/gms_output.so ./lib/postgresql/gms_profiler.so ./lib/postgresql/gms_sql.so +./lib/postgresql/gms_xmlgen.so ./lib/libpljava.so ./lib/libpq.a ./lib/libpq.so diff --git a/contrib/CMakeLists.txt b/contrib/CMakeLists.txt index 5ae029022..bbf7a935b 100644 --- a/contrib/CMakeLists.txt +++ b/contrib/CMakeLists.txt @@ -34,6 +34,13 @@ set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/gms_tcp ) +if("${USE_LIBXML}" STREQUAL "ON") + INCLUDE_DIRECTORIES(${LIBXML_INCLUDE_PATH}/libxml2) + INCLUDE_DIRECTORIES(${LIBXML_LIB_PATH}) + list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/gms_xmlgen) + add_subdirectory(gms_xmlgen) +endif() + add_subdirectory(hstore) add_subdirectory(test_decoding) add_subdirectory(mppdb_decoding) @@ -67,5 +74,4 @@ if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/chparser) add_subdirectory(chparser) endif() add_subdirectory(gms_profiler) - add_subdirectory(gms_lob) diff --git a/contrib/Makefile b/contrib/Makefile index 50d5d9c3b..a33ce11ba 100644 --- a/contrib/Makefile +++ b/contrib/Makefile @@ -70,8 +70,10 @@ endif ifeq ($(with_libxml),yes) SUBDIRS += xml2 +SUBDIRS += gms_xmlgen else ALWAYS_SUBDIRS += xml2 +ALWAYS_SUBDIRS += gms_xmlgen endif ifeq ($(with_selinux),yes) diff --git a/contrib/gms_xmlgen/CMakeLists.txt b/contrib/gms_xmlgen/CMakeLists.txt new file mode 100644 index 000000000..bd651ee9e --- /dev/null +++ b/contrib/gms_xmlgen/CMakeLists.txt @@ -0,0 +1,21 @@ +#This is the main CMAKE for build all gms_xmlgen. +# gms_xmlgen +AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR} TGT_gms_xmlgen_SRC) +set(TGT_gms_xmlgen_INC + ${PROJECT_OPENGS_DIR}/contrib/gms_xmlgen + ${PROJECT_OPENGS_DIR}/contrib +) + +set(gms_xmlgen_DEF_OPTIONS ${MACRO_OPTIONS}) +set(gms_xmlgen_COMPILE_OPTIONS ${OPTIMIZE_OPTIONS} ${OS_OPTIONS} ${PROTECT_OPTIONS} ${WARNING_OPTIONS} ${LIB_SECURE_OPTIONS} ${CHECK_OPTIONS}) +set(gms_xmlgen_LINK_OPTIONS ${LIB_LINK_OPTIONS}) +add_shared_libtarget(gms_xmlgen TGT_gms_xmlgen_SRC TGT_gms_xmlgen_INC "${gms_xmlgen_DEF_OPTIONS}" "${gms_xmlgen_COMPILE_OPTIONS}" "${gms_xmlgen_LINK_OPTIONS}") +set_target_properties(gms_xmlgen PROPERTIES PREFIX "") + +install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/gms_xmlgen.control + DESTINATION share/postgresql/extension/ +) +install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/gms_xmlgen--1.0.sql + DESTINATION share/postgresql/extension/ +) +install(TARGETS gms_xmlgen DESTINATION lib/postgresql) diff --git a/contrib/gms_xmlgen/Makefile b/contrib/gms_xmlgen/Makefile new file mode 100644 index 000000000..dcc2fd842 --- /dev/null +++ b/contrib/gms_xmlgen/Makefile @@ -0,0 +1,25 @@ +# contrib/gms_xmlgen/Makefile +MODULE_big = gms_xmlgen +OBJS = gms_xmlgen.o + +EXTENSION = gms_xmlgen +DATA = gms_xmlgen--1.0.sql + +exclude_option = -fPIE +top_builddir = ../.. +include $(top_builddir)/src/Makefile.global +override CPPFLAGS := -fstack-protector-strong $(filter-out $(exclude_option),$(CPPFLAGS)) -I$(LIBXML_INCLUDE_PATH)/libxml2 +REGRESS = gms_xmlgen + +ifdef USE_PGXS +PG_CONFIG = pg_config +PGXS := $(shell $(PG_CONFIG) --pgxs) +include $(PGXS) +else +subdir = contrib/gms_xmlgen +regress_home = $(top_builddir)/src/test/regress +REGRESS_OPTS = -c 0 -d 1 -r 1 -p 25633 --single_node -w --keep_last_data=false \ + --regconf=$(regress_home)/regress.conf \ + --temp-config=$(regress_home)/make_fastcheck_postgresql.conf +include $(top_srcdir)/contrib/contrib-global.mk +endif diff --git a/contrib/gms_xmlgen/data/dummy.txt b/contrib/gms_xmlgen/data/dummy.txt new file mode 100644 index 000000000..7f015cede --- /dev/null +++ b/contrib/gms_xmlgen/data/dummy.txt @@ -0,0 +1 @@ +The openGauss regression needs this file to run. \ No newline at end of file diff --git a/contrib/gms_xmlgen/expected/gms_xmlgen.out b/contrib/gms_xmlgen/expected/gms_xmlgen.out new file mode 100644 index 000000000..2a8115722 --- /dev/null +++ b/contrib/gms_xmlgen/expected/gms_xmlgen.out @@ -0,0 +1,3260 @@ +create extension gms_xmlgen; +create extension gms_output; +select gms_output.enable(100000); + enable +-------- + +(1 row) + +create schema gms_xmlgen_test; +set search_path = gms_xmlgen_test; +set behavior_compat_options = 'bind_procedure_searchpath'; +-- prepare data +create table t_types ( + "integer" integer, + "float" float, + "numeric" numeric(20, 6), + "boolean" boolean, + "char" char(20), + "varchar" varchar(20), + "text" text, + "blob" blob, + "raw" raw, + "date" date, + "time" time, + "timestamp" timestamp, + "json" json, + "varchar_array" varchar(20)[] +); +insert into t_types +values( + 1, + 1.23456, + 1.234567, + true, + '"''<>&char test', + 'varchar"''<>&test', + 'text test"''<>&', + 'ff', + hextoraw('ABCD'), + '2024-01-02', + '18:01:02', + '2024-02-03 19:03:04', + '{"a" : 1, "b" : 2}', + array['abc', '"''<>&', '你好'] + ), + ( + 2, + 2.23456, + 2.234567, + false, + '2"''<>&char test', + '2varchar"''<>&test', + '2text test"''<>&', + 'eeee', + hextoraw('ffff'), + '2026-03-04', + '20:12:13', + '2026-05-06 21:13:00', + '[9,8,7,6]', + array['&^%@', '"''<>&', '<&y''">'] + ), + ( + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null + ); +-- GMS_XMLGEN.NEWCONTEXT && GMS_XMLGEN.CLOSECONTEXT +select gms_xmlgen.newcontext('select * from t_types'); + newcontext +------------ + 1 +(1 row) + +select gms_xmlgen.getxml(1); + getxml +-------------------------------------------------------------- + + + + + + + 1 + + 1.23456 + + 1.234567 + + true + + "'<>&char test + + varchar"'<>&test + + text test"'<>& + + FF + + ABCD + + 2024-01-02T00:00:00 + + + + 2024-02-03T19:03:04 + + {"a" : 1, "b" : 2} + + + + abc + + "'<>& + + 你好 + + + + + + + + 2 + + 2.23456 + + 2.234567 + + false + + 2"'<>&char test + + 2varchar"'<>&test+ + 2text test"'<>& + + EEEE + + FFFF + + 2026-03-04T00:00:00 + + + + 2026-05-06T21:13:00 + + [9,8,7,6] + + + + &^%@ + + "'<>& + + <&y'"> + + + + + + + + + + + + +(1 row) + +select gms_xmlgen.closecontext(1); + closecontext +-------------- + +(1 row) + +-- procedure case +DECLARE +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.closecontext(xml_cxt); +END; +/ +-- newcontext by cursor +DECLARE +CURSOR xc is select * from t_types; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('xc'::refcursor); +gms_xmlgen.closecontext(xml_cxt); +END; +/ +-- newcontext by cursor expression +DECLARE +CURSOR xc is select "integer", CURSOR(select * from t_types) from t_types; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +open xc; +xml_cxt := gms_xmlgen.newcontext(xc); +gms_xmlgen.closecontext(xml_cxt); +close xc; +END; +/ +-- invalid null parameter +select gms_xmlgen.newcontext(NULL); +ERROR: invalid query string +CONTEXT: referenced column: newcontext +-- ok for invalid query sql +select gms_xmlgen.newcontext('aabbccdd'); + newcontext +------------ + 5 +(1 row) + +-- ok for closecontext NULL +select gms_xmlgen.closecontext(NULL); + closecontext +-------------- + +(1 row) + +-- ok for closecontext not exist id +select gms_xmlgen.closecontext(99); + closecontext +-------------- + +(1 row) + +-- error for closecontext invalid range +select gms_xmlgen.closecontext(-1); +ERROR: value is out of range. +CONTEXT: SQL statement "CALL gms_xmlgen.close_context(ctx)" +PL/pgSQL function gms_xmlgen.closecontext(gms_xmlgen.ctxhandle) line 2 at PERFORM +referenced column: closecontext +select gms_xmlgen.closecontext(4294967296); +ERROR: value is out of range. +CONTEXT: SQL statement "CALL gms_xmlgen.close_context(ctx)" +PL/pgSQL function gms_xmlgen.closecontext(gms_xmlgen.ctxhandle) line 2 at PERFORM +referenced column: closecontext +-- GMS_XMLGEN.GETXML +-- getxml by query +DECLARE +xml_output clob; +BEGIN +xml_output := gms_xmlgen.getxml('select * from t_types'); +gms_output.put_line(xml_output); +END; +/ + + + + 1 + 1.23456 + 1.234567 + true + "'<>&char test + varchar"'<>&test + text test"'<>& + FF + ABCD + 2024-01-02T00:00:00 + + 2024-02-03T19:03:04 + {"a" : 1, "b" : 2} + + abc + "'<>& + 你好 + + + + 2 + 2.23456 + 2.234567 + false + 2"'<>&char test + 2varchar"'<>&test + 2text test"'<>& + EEEE + FFFF + 2026-03-04T00:00:00 + + 2026-05-06T21:13:00 + [9,8,7,6] + + &^%@ + "'<>& + <&y'"> + + + + + + +-- getxml by cursor +DECLARE +CURSOR xc is select * from t_types; +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +open xc; +xml_cxt := gms_xmlgen.newcontext(xc); +xml_output := gms_xmlgen.getxml(xml_cxt); +gms_output.put_line(xml_output); +close xc; +gms_xmlgen.closecontext(xml_cxt); +END; +/ + + + + 1 + 1.23456 + 1.234567 + true + "'<>&char test + varchar"'<>&test + text test"'<>& + FF + ABCD + 2024-01-02T00:00:00 + + 2024-02-03T19:03:04 + {"a" : 1, "b" : 2} + + abc + "'<>& + 你好 + + + + 2 + 2.23456 + 2.234567 + false + 2"'<>&char test + 2varchar"'<>&test + 2text test"'<>& + EEEE + FFFF + 2026-03-04T00:00:00 + + 2026-05-06T21:13:00 + [9,8,7,6] + + &^%@ + "'<>& + <&y'"> + + + + + + +-- getxml by cursor expression +DECLARE +CURSOR xc is select "integer", CURSOR(select * from t_types) from t_types; +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +open xc; +xml_cxt := gms_xmlgen.newcontext(xc); +xml_output := gms_xmlgen.getxml(xml_cxt); +gms_output.put_line(xml_output); +close xc; +gms_xmlgen.closecontext(xml_cxt); +END; +/ + + + + 1 + <_x003F_column_x003F_><unnamed portal 6> + + + 2 + <_x003F_column_x003F_><unnamed portal 7> + + + <_x003F_column_x003F_><unnamed portal 8> + + + +-- getxml by context id +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +xml_output := gms_xmlgen.getxml(xml_cxt); +gms_output.put_line(xml_output); +gms_xmlgen.closecontext(xml_cxt); +END; +/ + + + + 1 + 1.23456 + 1.234567 + true + "'<>&char test + varchar"'<>&test + text test"'<>& + FF + ABCD + 2024-01-02T00:00:00 + + 2024-02-03T19:03:04 + {"a" : 1, "b" : 2} + + abc + "'<>& + 你好 + + + + 2 + 2.23456 + 2.234567 + false + 2"'<>&char test + 2varchar"'<>&test + 2text test"'<>& + EEEE + FFFF + 2026-03-04T00:00:00 + + 2026-05-06T21:13:00 + [9,8,7,6] + + &^%@ + "'<>& + <&y'"> + + + + + + +-- getxml by context id with out parameter +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.getxml(xml_cxt, xml_output); +gms_output.put_line(xml_output); +gms_xmlgen.closecontext(xml_cxt); +END; +/ + + + + 1 + 1.23456 + 1.234567 + true + "'<>&char test + varchar"'<>&test + text test"'<>& + FF + ABCD + 2024-01-02T00:00:00 + + 2024-02-03T19:03:04 + {"a" : 1, "b" : 2} + + abc + "'<>& + 你好 + + + + 2 + 2.23456 + 2.234567 + false + 2"'<>&char test + 2varchar"'<>&test + 2text test"'<>& + EEEE + FFFF + 2026-03-04T00:00:00 + + 2026-05-06T21:13:00 + [9,8,7,6] + + &^%@ + "'<>& + <&y'"> + + + + + + +-- no result when getxml twice without restartquery +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.getxml(xml_cxt); +xml_output := gms_xmlgen.getxml(xml_cxt); +gms_output.put_line(xml_output); +gms_xmlgen.closecontext(xml_cxt); +END; +/ +-- invalid null parameter +select gms_xmlgen.getxml(NULL); +ERROR: invalid query string +CONTEXT: referenced column: getxml +-- invalid query sql +select gms_xmlgen.getxml('aabbccdd'); +ERROR: syntax error at or near "aabbccdd" +LINE 1: select gms_xmlgen.getxml('aabbccdd'); + ^ +CONTEXT: referenced column: getxml +-- invalid xmlgen context id +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.closecontext(xml_cxt); +xml_output := gms_xmlgen.getxml(xml_cxt); +END; +/ +ERROR: invalid gms_xmlgen context found +CONTEXT: PL/pgSQL function inline_code_block line 6 at assignment +-- invalid xmlgen context id with out parameter +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.closecontext(xml_cxt); +gms_xmlgen.getxml(xml_cxt, xml_output); +gms_output.put_line(xml_output); +END; +/ +ERROR: invalid gms_xmlgen context found +CONTEXT: PL/pgSQL function gms_xmlgen.getxml(gms_xmlgen.ctxhandle,clob,numeric) line 2 at assignment +SQL statement "CALL gms_xmlgen.getxml(xml_cxt,xml_output)" +PL/pgSQL function inline_code_block line 6 at SQL statement +-- GMS_XMLGEN.GETXMLTYPE +-- getxmltype by query +DECLARE +xml_cxt gms_xmlgen.ctxhandle; +xml_type xmltype; +BEGIN +xml_type := gms_xmlgen.getxmltype('select * from t_types'); +gms_output.put_line(xml_type::text); +gms_xmlgen.closecontext(xml_cxt); +END; +/ + + + + 1 + 1.23456 + 1.234567 + true + "'<>&char test + varchar"'<>&test + text test"'<>& + FF + ABCD + 2024-01-02T00:00:00 + + 2024-02-03T19:03:04 + {"a" : 1, "b" : 2} + + abc + "'<>& + 你好 + + + + 2 + 2.23456 + 2.234567 + false + 2"'<>&char test + 2varchar"'<>&test + 2text test"'<>& + EEEE + FFFF + 2026-03-04T00:00:00 + + 2026-05-06T21:13:00 + [9,8,7,6] + + &^%@ + "'<>& + <&y'"> + + + + + + +-- getxmltype by query with parameter 2 +DECLARE +xml_cxt gms_xmlgen.ctxhandle; +xml_type xmltype; +BEGIN +xml_type := gms_xmlgen.getxmltype('select * from t_types', 1); +gms_output.put_line(xml_type::text); +gms_xmlgen.closecontext(xml_cxt); +END; +/ + + + + 1 + 1.23456 + 1.234567 + true + "'<>&char test + varchar"'<>&test + text test"'<>& + FF + ABCD + 2024-01-02T00:00:00 + + 2024-02-03T19:03:04 + {"a" : 1, "b" : 2} + + abc + "'<>& + 你好 + + + + 2 + 2.23456 + 2.234567 + false + 2"'<>&char test + 2varchar"'<>&test + 2text test"'<>& + EEEE + FFFF + 2026-03-04T00:00:00 + + 2026-05-06T21:13:00 + [9,8,7,6] + + &^%@ + "'<>& + <&y'"> + + + + + + +-- getxmltype by context id +DECLARE +xml_cxt gms_xmlgen.ctxhandle; +xml_type xmltype; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +xml_type := gms_xmlgen.getxmltype(xml_cxt); +gms_output.put_line(xml_type::text); +gms_xmlgen.closecontext(xml_cxt); +END; +/ + + + + 1 + 1.23456 + 1.234567 + true + "'<>&char test + varchar"'<>&test + text test"'<>& + FF + ABCD + 2024-01-02T00:00:00 + + 2024-02-03T19:03:04 + {"a" : 1, "b" : 2} + + abc + "'<>& + 你好 + + + + 2 + 2.23456 + 2.234567 + false + 2"'<>&char test + 2varchar"'<>&test + 2text test"'<>& + EEEE + FFFF + 2026-03-04T00:00:00 + + 2026-05-06T21:13:00 + [9,8,7,6] + + &^%@ + "'<>& + <&y'"> + + + + + + +-- getxmltype by context id with parameter 2 +DECLARE +xml_cxt gms_xmlgen.ctxhandle; +xml_type xmltype; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +xml_type := gms_xmlgen.getxmltype(xml_cxt, 1); +gms_output.put_line(xml_type::text); +gms_xmlgen.closecontext(xml_cxt); +END; +/ + + + + 1 + 1.23456 + 1.234567 + true + "'<>&char test + varchar"'<>&test + text test"'<>& + FF + ABCD + 2024-01-02T00:00:00 + + 2024-02-03T19:03:04 + {"a" : 1, "b" : 2} + + abc + "'<>& + 你好 + + + + 2 + 2.23456 + 2.234567 + false + 2"'<>&char test + 2varchar"'<>&test + 2text test"'<>& + EEEE + FFFF + 2026-03-04T00:00:00 + + 2026-05-06T21:13:00 + [9,8,7,6] + + &^%@ + "'<>& + <&y'"> + + + + + + +-- getxmltype by cursor +DECLARE +CURSOR xc is select * from t_types; +xml_cxt gms_xmlgen.ctxhandle; +xml_output xmltype; +BEGIN +open xc; +xml_cxt := gms_xmlgen.newcontext(xc); +xml_output := gms_xmlgen.getxmltype(xml_cxt); +gms_output.put_line(xml_output::text); +close xc; +gms_xmlgen.closecontext(xml_cxt); +END; +/ + + + + 1 + 1.23456 + 1.234567 + true + "'<>&char test + varchar"'<>&test + text test"'<>& + FF + ABCD + 2024-01-02T00:00:00 + + 2024-02-03T19:03:04 + {"a" : 1, "b" : 2} + + abc + "'<>& + 你好 + + + + 2 + 2.23456 + 2.234567 + false + 2"'<>&char test + 2varchar"'<>&test + 2text test"'<>& + EEEE + FFFF + 2026-03-04T00:00:00 + + 2026-05-06T21:13:00 + [9,8,7,6] + + &^%@ + "'<>& + <&y'"> + + + + + + +-- getxmltype by cursor expression +DECLARE +CURSOR xc is select "integer", CURSOR(select * from t_types) from t_types; +xml_cxt gms_xmlgen.ctxhandle; +xml_output xmltype; +BEGIN +open xc; +xml_cxt := gms_xmlgen.newcontext(xc); +xml_output := gms_xmlgen.getxmltype(xml_cxt); +gms_output.put_line(xml_output::text); +close xc; +gms_xmlgen.closecontext(xml_cxt); +END; +/ + + + + 1 + <_x003F_column_x003F_><unnamed portal 19> + + + 2 + <_x003F_column_x003F_><unnamed portal 20> + + + <_x003F_column_x003F_><unnamed portal 21> + + + +-- invalid null parameter +select gms_xmlgen.getxmltype(NULL); +ERROR: invalid query string +CONTEXT: referenced column: getxmltype +-- invalid query sql +select gms_xmlgen.getxmltype('aabbccdd'); +ERROR: syntax error at or near "aabbccdd" +LINE 1: select gms_xmlgen.getxmltype('aabbccdd'); + ^ +CONTEXT: referenced column: getxmltype +-- invalid context id +DECLARE +xml_cxt gms_xmlgen.ctxhandle; +xml_type xmltype; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.closecontext(xml_cxt); +xml_type := gms_xmlgen.getxmltype(xml_cxt); +END; +/ +ERROR: invalid gms_xmlgen context found +CONTEXT: PL/pgSQL function inline_code_block line 6 at assignment +-- invalid parameter 2 range +select gms_xmlgen.getxmltype('select * from t_types', -1); +ERROR: value is out of range. +CONTEXT: referenced column: getxmltype +select gms_xmlgen.getxmltype('select * from t_types', 4294967296); +ERROR: value is out of range. +CONTEXT: referenced column: getxmltype +-- GMS_XMLGEN.NEWCONTEXTFROMHIERARCHY +DECLARE +xml_output clob; +xml_cxt_from_hierarchy gms_xmlgen.ctxhandle; +BEGIN +xml_cxt_from_hierarchy := gms_xmlgen.newcontextfromhierarchy(' +SELECT "integer", xmltype(gms_xmlgen.getxml(''select * from t_types'')) +FROM t_types +START WITH "integer" = 1 OR "integer" = 2 +CONNECT BY nocycle "integer" = PRIOR "integer"'); +xml_output := gms_xmlgen.getxml(xml_cxt_from_hierarchy); +gms_output.put_line(xml_output); +gms_xmlgen.closecontext(xml_cxt_from_hierarchy); +END; +/ + + + + 1 + 1.23456 + 1.234567 + true + "'<>&char test + varchar"'<>&test + text test"'<>& + FF + ABCD + 2024-01-02T00:00:00 + + 2024-02-03T19:03:04 + {"a" : 1, "b" : 2} + + abc + "'<>& + 你好 + + + + 2 + 2.23456 + 2.234567 + false + 2"'<>&char test + 2varchar"'<>&test + 2text test"'<>& + EEEE + FFFF + 2026-03-04T00:00:00 + + 2026-05-06T21:13:00 + [9,8,7,6] + + &^%@ + "'<>& + <&y'"> + + + + + + + 1 + 1.23456 + 1.234567 + true + "'<>&char test + varchar"'<>&test + text test"'<>& + FF + ABCD + 2024-01-02T00:00:00 + + 2024-02-03T19:03:04 + {"a" : 1, "b" : 2} + + abc + "'<>& + 你好 + + + + 2 + 2.23456 + 2.234567 + false + 2"'<>&char test + 2varchar"'<>&test + 2text test"'<>& + EEEE + FFFF + 2026-03-04T00:00:00 + + 2026-05-06T21:13:00 + [9,8,7,6] + + &^%@ + "'<>& + <&y'"> + + + + + + +-- with set row set tag +DECLARE +xml_output clob; +xml_cxt_from_hierarchy gms_xmlgen.ctxhandle; +BEGIN +xml_cxt_from_hierarchy := gms_xmlgen.newcontextfromhierarchy(' +SELECT "integer", xmltype(gms_xmlgen.getxml(''select * from t_types'')) +FROM t_types +START WITH "integer" = 1 OR "integer" = 2 +CONNECT BY nocycle "integer" = PRIOR "integer"'); +gms_xmlgen.setrowsettag(xml_cxt_from_hierarchy, 'TopTag'); +xml_output := gms_xmlgen.getxml(xml_cxt_from_hierarchy); +gms_output.put_line(xml_output); +gms_xmlgen.closecontext(xml_cxt_from_hierarchy); +END; +/ + + + + + 1 + 1.23456 + 1.234567 + true + "'<>&char test + varchar"'<>&test + text test"'<>& + FF + ABCD + 2024-01-02T00:00:00 + + 2024-02-03T19:03:04 + {"a" : 1, "b" : 2} + + abc + "'<>& + 你好 + + + + 2 + 2.23456 + 2.234567 + false + 2"'<>&char test + 2varchar"'<>&test + 2text test"'<>& + EEEE + FFFF + 2026-03-04T00:00:00 + + 2026-05-06T21:13:00 + [9,8,7,6] + + &^%@ + "'<>& + <&y'"> + + + + + + + 1 + 1.23456 + 1.234567 + true + "'<>&char test + varchar"'<>&test + text test"'<>& + FF + ABCD + 2024-01-02T00:00:00 + + 2024-02-03T19:03:04 + {"a" : 1, "b" : 2} + + abc + "'<>& + 你好 + + + + 2 + 2.23456 + 2.234567 + false + 2"'<>&char test + 2varchar"'<>&test + 2text test"'<>& + EEEE + FFFF + 2026-03-04T00:00:00 + + 2026-05-06T21:13:00 + [9,8,7,6] + + &^%@ + "'<>& + <&y'"> + + + + + + + +-- error with set row tag +DECLARE +xml_output clob; +xml_cxt_from_hierarchy gms_xmlgen.ctxhandle; +BEGIN +xml_cxt_from_hierarchy := gms_xmlgen.newcontextfromhierarchy(' +SELECT "integer", xmltype(gms_xmlgen.getxml(''select * from t_types'')) +FROM t_types +START WITH "integer" = 1 OR "integer" = 2 +CONNECT BY nocycle "integer" = PRIOR "integer"'); +gms_xmlgen.setrowtag(xml_cxt_from_hierarchy, 'TopTag'); +xml_output := gms_xmlgen.getxml(xml_cxt_from_hierarchy); +gms_output.put_line(xml_output); +gms_xmlgen.closecontext(xml_cxt_from_hierarchy); +END; +/ +ERROR: this operation is invalid in the hierarchy context +CONTEXT: SQL statement "CALL gms_xmlgen.set_row_tag(ctx,rowTagName)" +PL/pgSQL function gms_xmlgen.setrowtag(gms_xmlgen.ctxhandle,character varying) line 2 at PERFORM +SQL statement "CALL gms_xmlgen.setrowtag(xml_cxt_from_hierarchy,'TopTag')" +PL/pgSQL function inline_code_block line 9 at PERFORM +-- error with setmaxrows +DECLARE +xml_output clob; +xml_cxt_from_hierarchy gms_xmlgen.ctxhandle; +BEGIN +xml_cxt_from_hierarchy := gms_xmlgen.newcontextfromhierarchy(' +SELECT "integer", xmltype(gms_xmlgen.getxml(''select * from t_types'')) +FROM t_types +START WITH "integer" = 1 OR "integer" = 2 +CONNECT BY nocycle "integer" = PRIOR "integer"'); +gms_xmlgen.setmaxrows(xml_cxt_from_hierarchy, 1); +xml_output := gms_xmlgen.getxml(xml_cxt_from_hierarchy); +gms_output.put_line(xml_output); +gms_xmlgen.closecontext(xml_cxt_from_hierarchy); +END; +/ +ERROR: this operation is invalid in the hierarchy context +CONTEXT: SQL statement "CALL gms_xmlgen.set_max_rows(ctx,maxrows)" +PL/pgSQL function gms_xmlgen.setmaxrows(gms_xmlgen.ctxhandle,numeric) line 2 at PERFORM +SQL statement "CALL gms_xmlgen.setmaxrows(xml_cxt_from_hierarchy,1)" +PL/pgSQL function inline_code_block line 9 at PERFORM +-- error with setskiprows +DECLARE +xml_output clob; +xml_cxt_from_hierarchy gms_xmlgen.ctxhandle; +BEGIN +xml_cxt_from_hierarchy := gms_xmlgen.newcontextfromhierarchy(' +SELECT "integer", xmltype(gms_xmlgen.getxml(''select * from t_types'')) +FROM t_types +START WITH "integer" = 1 OR "integer" = 2 +CONNECT BY nocycle "integer" = PRIOR "integer"'); +gms_xmlgen.setskiprows(xml_cxt_from_hierarchy, 1); +xml_output := gms_xmlgen.getxml(xml_cxt_from_hierarchy); +gms_output.put_line(xml_output); +gms_xmlgen.closecontext(xml_cxt_from_hierarchy); +END; +/ +ERROR: this operation is invalid in the hierarchy context +CONTEXT: SQL statement "CALL gms_xmlgen.set_skip_rows(ctx,skipRows)" +PL/pgSQL function gms_xmlgen.setskiprows(gms_xmlgen.ctxhandle,numeric) line 2 at PERFORM +SQL statement "CALL gms_xmlgen.setskiprows(xml_cxt_from_hierarchy,1)" +PL/pgSQL function inline_code_block line 9 at PERFORM +-- invalid null parameter +select gms_xmlgen.newcontextfromhierarchy(NULL); +ERROR: invalid query string +CONTEXT: referenced column: newcontextfromhierarchy +-- ok for invalid query sql +select gms_xmlgen.newcontextfromhierarchy('aabbccdd'); + newcontextfromhierarchy +------------------------- + 23 +(1 row) + +-- get xml error with invalid query sql +DECLARE +xml_output clob; +xml_cxt_from_hierarchy gms_xmlgen.ctxhandle; +BEGIN +xml_cxt_from_hierarchy := gms_xmlgen.newcontextfromhierarchy('aabbccdd'); +xml_output := gms_xmlgen.getxml(xml_cxt_from_hierarchy); +gms_output.put_line(xml_output); +gms_xmlgen.closecontext(xml_cxt_from_hierarchy); +END; +/ +ERROR: syntax error at or near "aabbccdd" +LINE 1: aabbccdd + ^ +QUERY: aabbccdd +CONTEXT: PL/pgSQL function inline_code_block line 5 at assignment +-- get xml error with not hierarchy query sql +DECLARE +xml_output clob; +xml_cxt_from_hierarchy gms_xmlgen.ctxhandle; +BEGIN +xml_cxt_from_hierarchy := gms_xmlgen.newcontextfromhierarchy('select * from t_types'); +xml_output := gms_xmlgen.getxml(xml_cxt_from_hierarchy); +gms_output.put_line(xml_output); +gms_xmlgen.closecontext(xml_cxt_from_hierarchy); +END; +/ +ERROR: invalid query result +CONTEXT: PL/pgSQL function inline_code_block line 5 at assignment +-- GMS_XMLGEN.RESTARTQUERY +-- get xml twice +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +xml_output := gms_xmlgen.getxml(xml_cxt); +gms_output.put_line(xml_output); +gms_xmlgen.restartquery(xml_cxt); +xml_output := gms_xmlgen.getxml(xml_cxt); +gms_output.put_line(xml_output); +gms_xmlgen.closecontext(xml_cxt); +END; +/ + + + + 1 + 1.23456 + 1.234567 + true + "'<>&char test + varchar"'<>&test + text test"'<>& + FF + ABCD + 2024-01-02T00:00:00 + + 2024-02-03T19:03:04 + {"a" : 1, "b" : 2} + + abc + "'<>& + 你好 + + + + 2 + 2.23456 + 2.234567 + false + 2"'<>&char test + 2varchar"'<>&test + 2text test"'<>& + EEEE + FFFF + 2026-03-04T00:00:00 + + 2026-05-06T21:13:00 + [9,8,7,6] + + &^%@ + "'<>& + <&y'"> + + + + + + + + + + 1 + 1.23456 + 1.234567 + true + "'<>&char test + varchar"'<>&test + text test"'<>& + FF + ABCD + 2024-01-02T00:00:00 + + 2024-02-03T19:03:04 + {"a" : 1, "b" : 2} + + abc + "'<>& + 你好 + + + + 2 + 2.23456 + 2.234567 + false + 2"'<>&char test + 2varchar"'<>&test + 2text test"'<>& + EEEE + FFFF + 2026-03-04T00:00:00 + + 2026-05-06T21:13:00 + [9,8,7,6] + + &^%@ + "'<>& + <&y'"> + + + + + + +-- ok for restartquery closed context id +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.closecontext(xml_cxt); +gms_xmlgen.restartquery(xml_cxt); +END; +/ +-- GMS_XMLGEN.SETCONVERTSPECIALCHARS +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.setconvertspecialchars(xml_cxt, false); +xml_output := gms_xmlgen.getxml(xml_cxt); +gms_output.put_line(xml_output); +gms_xmlgen.setconvertspecialchars(xml_cxt, true); +gms_xmlgen.restartquery(xml_cxt); +xml_output := gms_xmlgen.getxml(xml_cxt); +gms_output.put_line(xml_output); +gms_xmlgen.closecontext(xml_cxt); +END; +/ + + + + 1 + 1.23456 + 1.234567 + true + "'<>&char test + varchar"'<>&test + text test"'<>& + FF + ABCD + 2024-01-02T00:00:00 + + 2024-02-03T19:03:04 + {"a" : 1, "b" : 2} + + abc + "'<>& + 你好 + + + + 2 + 2.23456 + 2.234567 + false + 2"'<>&char test + 2varchar"'<>&test + 2text test"'<>& + EEEE + FFFF + 2026-03-04T00:00:00 + + 2026-05-06T21:13:00 + [9,8,7,6] + + &^%@ + "'<>& + <&y'"> + + + + + + + + + + 1 + 1.23456 + 1.234567 + true + "'<>&char test + varchar"'<>&test + text test"'<>& + FF + ABCD + 2024-01-02T00:00:00 + + 2024-02-03T19:03:04 + {"a" : 1, "b" : 2} + + abc + "'<>& + 你好 + + + + 2 + 2.23456 + 2.234567 + false + 2"'<>&char test + 2varchar"'<>&test + 2text test"'<>& + EEEE + FFFF + 2026-03-04T00:00:00 + + 2026-05-06T21:13:00 + [9,8,7,6] + + &^%@ + "'<>& + <&y'"> + + + + + + +-- error for missing parameter 2 +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.setconvertspecialchars(xml_cxt); +gms_xmlgen.closecontext(xml_cxt); +END; +/ +ERROR: function gms_xmlgen.setconvertspecialchars has no enough parameters +CONTEXT: compilation of PL/pgSQL function "inline_code_block" near line 4 +-- ok for closed context +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.closecontext(xml_cxt); +gms_xmlgen.setconvertspecialchars(xml_cxt, true); +END; +/ +-- GMS_XMLGEN.SETMAXROWS +-- set max rows 0 +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.setmaxrows(xml_cxt, 0); +xml_output := gms_xmlgen.getxml(xml_cxt); +gms_output.put_line(xml_output); +gms_xmlgen.closecontext(xml_cxt); +END; +/ +-- set max rows 1 +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.setmaxrows(xml_cxt, 1); +xml_output := gms_xmlgen.getxml(xml_cxt); +gms_output.put_line(xml_output); +gms_xmlgen.closecontext(xml_cxt); +END; +/ + + + + 1 + 1.23456 + 1.234567 + true + "'<>&char test + varchar"'<>&test + text test"'<>& + FF + ABCD + 2024-01-02T00:00:00 + + 2024-02-03T19:03:04 + {"a" : 1, "b" : 2} + + abc + "'<>& + 你好 + + + + +-- parameter nums error +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.setmaxrows(xml_cxt); +gms_xmlgen.closecontext(xml_cxt); +END; +/ +ERROR: function gms_xmlgen.setmaxrows has no enough parameters +CONTEXT: compilation of PL/pgSQL function "inline_code_block" near line 4 +-- parameter range error +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.setmaxrows(xml_cxt, -1); +gms_xmlgen.closecontext(xml_cxt); +END; +/ +ERROR: value is out of range. +CONTEXT: SQL statement "CALL gms_xmlgen.set_max_rows(ctx,maxrows)" +PL/pgSQL function gms_xmlgen.setmaxrows(gms_xmlgen.ctxhandle,numeric) line 2 at PERFORM +SQL statement "CALL gms_xmlgen.setmaxrows(xml_cxt,-1)" +PL/pgSQL function inline_code_block line 5 at PERFORM +-- parameter range error +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.setmaxrows(xml_cxt, 4294967296); +gms_xmlgen.closecontext(xml_cxt); +END; +/ +ERROR: value is out of range. +CONTEXT: SQL statement "CALL gms_xmlgen.set_max_rows(ctx,maxrows)" +PL/pgSQL function gms_xmlgen.setmaxrows(gms_xmlgen.ctxhandle,numeric) line 2 at PERFORM +SQL statement "CALL gms_xmlgen.setmaxrows(xml_cxt,4294967296)" +PL/pgSQL function inline_code_block line 5 at PERFORM +-- ok for closed context +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.closecontext(xml_cxt); +gms_xmlgen.setmaxrows(xml_cxt, 1); +END; +/ +-- GMS_XMLGEN.SETNULLHANDLING +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.setnullhandling(xml_cxt, 0); +xml_output := gms_xmlgen.getxml(xml_cxt); +gms_output.put_line(xml_output); +gms_xmlgen.setnullhandling(xml_cxt, 1); +gms_xmlgen.restartquery(xml_cxt); +xml_output := gms_xmlgen.getxml(xml_cxt); +gms_output.put_line(xml_output); +gms_xmlgen.setnullhandling(xml_cxt, 2); +gms_xmlgen.restartquery(xml_cxt); +xml_output := gms_xmlgen.getxml(xml_cxt); +gms_output.put_line(xml_output); +gms_xmlgen.closecontext(xml_cxt); +END; +/ + + + + 1 + 1.23456 + 1.234567 + true + "'<>&char test + varchar"'<>&test + text test"'<>& + FF + ABCD + 2024-01-02T00:00:00 + + 2024-02-03T19:03:04 + {"a" : 1, "b" : 2} + + abc + "'<>& + 你好 + + + + 2 + 2.23456 + 2.234567 + false + 2"'<>&char test + 2varchar"'<>&test + 2text test"'<>& + EEEE + FFFF + 2026-03-04T00:00:00 + + 2026-05-06T21:13:00 + [9,8,7,6] + + &^%@ + "'<>& + <&y'"> + + + + + + + + + + 1 + 1.23456 + 1.234567 + true + "'<>&char test + varchar"'<>&test + text test"'<>& + FF + ABCD + 2024-01-02T00:00:00 + + 2024-02-03T19:03:04 + {"a" : 1, "b" : 2} + + abc + "'<>& + 你好 + + + + 2 + 2.23456 + 2.234567 + false + 2"'<>&char test + 2varchar"'<>&test + 2text test"'<>& + EEEE + FFFF + 2026-03-04T00:00:00 + + 2026-05-06T21:13:00 + [9,8,7,6] + + &^%@ + "'<>& + <&y'"> + + + + + + + + + + + + + + + + + + + + 1 + 1.23456 + 1.234567 + true + "'<>&char test + varchar"'<>&test + text test"'<>& + FF + ABCD + 2024-01-02T00:00:00 + + 2024-02-03T19:03:04 + {"a" : 1, "b" : 2} + + abc + "'<>& + 你好 + + + + 2 + 2.23456 + 2.234567 + false + 2"'<>&char test + 2varchar"'<>&test + 2text test"'<>& + EEEE + FFFF + 2026-03-04T00:00:00 + + 2026-05-06T21:13:00 + [9,8,7,6] + + &^%@ + "'<>& + <&y'"> + + + + + + + + + + + + + + + + +-- other numbers > 2, the same as 0 +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.setnullhandling(xml_cxt, 3); +xml_output := gms_xmlgen.getxml(xml_cxt); +gms_output.put_line(xml_output); +gms_xmlgen.closecontext(xml_cxt); +END; +/ + + + + 1 + 1.23456 + 1.234567 + true + "'<>&char test + varchar"'<>&test + text test"'<>& + FF + ABCD + 2024-01-02T00:00:00 + + 2024-02-03T19:03:04 + {"a" : 1, "b" : 2} + + abc + "'<>& + 你好 + + + + 2 + 2.23456 + 2.234567 + false + 2"'<>&char test + 2varchar"'<>&test + 2text test"'<>& + EEEE + FFFF + 2026-03-04T00:00:00 + + 2026-05-06T21:13:00 + [9,8,7,6] + + &^%@ + "'<>& + <&y'"> + + + + + + +-- ok for NULL +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +gms_xmlgen.setnullhandling(NULL, 1); +END; +/ +-- parameter nums error +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.setnullhandling(xml_cxt); +gms_xmlgen.closecontext(xml_cxt); +END; +/ +ERROR: function gms_xmlgen.setnullhandling has no enough parameters +CONTEXT: compilation of PL/pgSQL function "inline_code_block" near line 4 +-- parameter range error +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.setnullhandling(xml_cxt, -1); +gms_xmlgen.closecontext(xml_cxt); +END; +/ +ERROR: value is out of range. +CONTEXT: SQL statement "CALL gms_xmlgen.set_null_handling(ctx,flag)" +PL/pgSQL function gms_xmlgen.setnullhandling(gms_xmlgen.ctxhandle,numeric) line 2 at PERFORM +SQL statement "CALL gms_xmlgen.setnullhandling(xml_cxt,-1)" +PL/pgSQL function inline_code_block line 5 at PERFORM +-- parameter range error +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.setnullhandling(xml_cxt, 4294967296); +gms_xmlgen.closecontext(xml_cxt); +END; +/ +ERROR: value is out of range. +CONTEXT: SQL statement "CALL gms_xmlgen.set_null_handling(ctx,flag)" +PL/pgSQL function gms_xmlgen.setnullhandling(gms_xmlgen.ctxhandle,numeric) line 2 at PERFORM +SQL statement "CALL gms_xmlgen.setnullhandling(xml_cxt,4294967296)" +PL/pgSQL function inline_code_block line 5 at PERFORM +-- ok for closed context +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.closecontext(xml_cxt); +gms_xmlgen.setnullhandling(xml_cxt, 1); +END; +/ +-- GMS_XMLGEN.SETROWSETTAG +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.setrowsettag(xml_cxt, 'test'); +xml_output := gms_xmlgen.getxml(xml_cxt); +gms_output.put_line(xml_output); +gms_xmlgen.closecontext(xml_cxt); +END; +/ + + + + 1 + 1.23456 + 1.234567 + true + "'<>&char test + varchar"'<>&test + text test"'<>& + FF + ABCD + 2024-01-02T00:00:00 + + 2024-02-03T19:03:04 + {"a" : 1, "b" : 2} + + abc + "'<>& + 你好 + + + + 2 + 2.23456 + 2.234567 + false + 2"'<>&char test + 2varchar"'<>&test + 2text test"'<>& + EEEE + FFFF + 2026-03-04T00:00:00 + + 2026-05-06T21:13:00 + [9,8,7,6] + + &^%@ + "'<>& + <&y'"> + + + + + + +-- error for setrowsettag NULL +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.setrowsettag(xml_cxt, NULL); +xml_output := gms_xmlgen.getxml(xml_cxt); +gms_output.put_line(xml_output); +gms_xmlgen.closecontext(xml_cxt); +END; +/ +ERROR: the xml has multiple root nodes +CONTEXT: PL/pgSQL function inline_code_block line 6 at assignment +-- ok for setrowsettag NULL with one row +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types where rownum = 1'); +gms_xmlgen.setrowsettag(xml_cxt, NULL); +xml_output := gms_xmlgen.getxml(xml_cxt); +gms_output.put_line(xml_output); +gms_xmlgen.closecontext(xml_cxt); +END; +/ + + + 1 + 1.23456 + 1.234567 + true + "'<>&char test + varchar"'<>&test + text test"'<>& + FF + ABCD + 2024-01-02T00:00:00 + + 2024-02-03T19:03:04 + {"a" : 1, "b" : 2} + + abc + "'<>& + 你好 + + + +-- ok for setrowsettag context id null +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +gms_xmlgen.setrowsettag(NULL, 'test'); +END; +/ +-- parameter nums error +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.setrowsettag(xml_cxt); +gms_xmlgen.closecontext(xml_cxt); +END; +/ +ERROR: function gms_xmlgen.setrowsettag has no enough parameters +CONTEXT: compilation of PL/pgSQL function "inline_code_block" near line 4 +-- parameter type error +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.setrowsettag(xml_cxt, true); +gms_xmlgen.closecontext(xml_cxt); +END; +/ +ERROR: function gms_xmlgen.setrowsettag(gms_xmlgen.ctxhandle, boolean) does not exist +HINT: No function matches the given name and argument types. You might need to add explicit type casts. +CONTEXT: SQL statement "CALL gms_xmlgen.setrowsettag(xml_cxt,true)" +PL/pgSQL function inline_code_block line 5 at PERFORM +-- ok for closed context +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.closecontext(xml_cxt); +gms_xmlgen.setrowsettag(xml_cxt, 'test'); +END; +/ +-- GMS_XMLGEN.SETROWTAG +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.setrowtag(xml_cxt, 'test'); +xml_output := gms_xmlgen.getxml(xml_cxt); +gms_output.put_line(xml_output); +gms_xmlgen.closecontext(xml_cxt); +END; +/ + + + + 1 + 1.23456 + 1.234567 + true + "'<>&char test + varchar"'<>&test + text test"'<>& + FF + ABCD + 2024-01-02T00:00:00 + + 2024-02-03T19:03:04 + {"a" : 1, "b" : 2} + + abc + "'<>& + 你好 + + + + 2 + 2.23456 + 2.234567 + false + 2"'<>&char test + 2varchar"'<>&test + 2text test"'<>& + EEEE + FFFF + 2026-03-04T00:00:00 + + 2026-05-06T21:13:00 + [9,8,7,6] + + &^%@ + "'<>& + <&y'"> + + + + + + +-- ok for setrowtag NULL +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.setrowtag(xml_cxt, NULL); +xml_output := gms_xmlgen.getxml(xml_cxt); +gms_output.put_line(xml_output); +gms_xmlgen.closecontext(xml_cxt); +END; +/ + + + 1 + 1.23456 + 1.234567 + true + "'<>&char test + varchar"'<>&test + text test"'<>& + FF + ABCD + 2024-01-02T00:00:00 + + 2024-02-03T19:03:04 + {"a" : 1, "b" : 2} + + abc + "'<>& + 你好 + + 2 + 2.23456 + 2.234567 + false + 2"'<>&char test + 2varchar"'<>&test + 2text test"'<>& + EEEE + FFFF + 2026-03-04T00:00:00 + + 2026-05-06T21:13:00 + [9,8,7,6] + + &^%@ + "'<>& + <&y'"> + + + +-- error for setrowsettag NULL && setrowtag NULL +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.setrowsettag(xml_cxt, NULL); +gms_xmlgen.setrowtag(xml_cxt, NULL); +xml_output := gms_xmlgen.getxml(xml_cxt); +gms_output.put_line(xml_output); +gms_xmlgen.closecontext(xml_cxt); +END; +/ +ERROR: the xml has multiple root nodes +CONTEXT: PL/pgSQL function inline_code_block line 7 at assignment +-- ok for setrowtag context id null +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +gms_xmlgen.setrowtag(NULL, 'test'); +END; +/ +-- parameter nums error +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.setrowtag(xml_cxt); +gms_xmlgen.closecontext(xml_cxt); +END; +/ +ERROR: function gms_xmlgen.setrowtag has no enough parameters +CONTEXT: compilation of PL/pgSQL function "inline_code_block" near line 4 +-- parameter type error +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.setrowtag(xml_cxt, true); +gms_xmlgen.closecontext(xml_cxt); +END; +/ +ERROR: function gms_xmlgen.setrowtag(gms_xmlgen.ctxhandle, boolean) does not exist +HINT: No function matches the given name and argument types. You might need to add explicit type casts. +CONTEXT: SQL statement "CALL gms_xmlgen.setrowtag(xml_cxt,true)" +PL/pgSQL function inline_code_block line 5 at PERFORM +-- ok for closed context +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.closecontext(xml_cxt); +gms_xmlgen.setrowtag(xml_cxt, 'test'); +END; +/ +-- GMS_XMLGEN.SETSKIPROWS +-- set skip row 0 +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.setskiprows(xml_cxt, 0); +xml_output := gms_xmlgen.getxml(xml_cxt); +gms_output.put_line(xml_output); +gms_xmlgen.closecontext(xml_cxt); +END; +/ + + + + 1 + 1.23456 + 1.234567 + true + "'<>&char test + varchar"'<>&test + text test"'<>& + FF + ABCD + 2024-01-02T00:00:00 + + 2024-02-03T19:03:04 + {"a" : 1, "b" : 2} + + abc + "'<>& + 你好 + + + + 2 + 2.23456 + 2.234567 + false + 2"'<>&char test + 2varchar"'<>&test + 2text test"'<>& + EEEE + FFFF + 2026-03-04T00:00:00 + + 2026-05-06T21:13:00 + [9,8,7,6] + + &^%@ + "'<>& + <&y'"> + + + + + + +-- set skip row 1 +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.setskiprows(xml_cxt, 1); +xml_output := gms_xmlgen.getxml(xml_cxt); +gms_output.put_line(xml_output); +gms_xmlgen.closecontext(xml_cxt); +END; +/ + + + + 2 + 2.23456 + 2.234567 + false + 2"'<>&char test + 2varchar"'<>&test + 2text test"'<>& + EEEE + FFFF + 2026-03-04T00:00:00 + + 2026-05-06T21:13:00 + [9,8,7,6] + + &^%@ + "'<>& + <&y'"> + + + + + + +-- set skip row 2 +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.setskiprows(xml_cxt, 2); +xml_output := gms_xmlgen.getxml(xml_cxt); +gms_output.put_line(xml_output); +gms_xmlgen.closecontext(xml_cxt); +END; +/ + + + + + + +-- ok for setskiprows context id null +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.setskiprows(NULL, 1); +gms_xmlgen.closecontext(xml_cxt); +END; +/ +-- parameter nums error +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.setskiprows(xml_cxt); +gms_xmlgen.closecontext(xml_cxt); +END; +/ +ERROR: function gms_xmlgen.setskiprows has no enough parameters +CONTEXT: compilation of PL/pgSQL function "inline_code_block" near line 4 +-- parameter range error +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.setskiprows(xml_cxt, -1); +gms_xmlgen.closecontext(xml_cxt); +END; +/ +ERROR: value is out of range. +CONTEXT: SQL statement "CALL gms_xmlgen.set_skip_rows(ctx,skipRows)" +PL/pgSQL function gms_xmlgen.setskiprows(gms_xmlgen.ctxhandle,numeric) line 2 at PERFORM +SQL statement "CALL gms_xmlgen.setskiprows(xml_cxt,-1)" +PL/pgSQL function inline_code_block line 5 at PERFORM +-- parameter range error +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.setskiprows(xml_cxt, 4294967296); +gms_xmlgen.closecontext(xml_cxt); +END; +/ +ERROR: value is out of range. +CONTEXT: SQL statement "CALL gms_xmlgen.set_skip_rows(ctx,skipRows)" +PL/pgSQL function gms_xmlgen.setskiprows(gms_xmlgen.ctxhandle,numeric) line 2 at PERFORM +SQL statement "CALL gms_xmlgen.setskiprows(xml_cxt,4294967296)" +PL/pgSQL function inline_code_block line 5 at PERFORM +-- ok for closed context +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.closecontext(xml_cxt); +gms_xmlgen.setskiprows(xml_cxt, 1); +END; +/ +-- GMS_XMLGEN.USEITEMTAGSFORCOLL +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.useitemtagsforcoll(xml_cxt); +xml_output := gms_xmlgen.getxml(xml_cxt); +gms_output.put_line(xml_output); +gms_xmlgen.closecontext(xml_cxt); +END; +/ + + + + 1 + 1.23456 + 1.234567 + true + "'<>&char test + varchar"'<>&test + text test"'<>& + FF + ABCD + 2024-01-02T00:00:00 + + 2024-02-03T19:03:04 + {"a" : 1, "b" : 2} + + abc + "'<>& + 你好 + + + + 2 + 2.23456 + 2.234567 + false + 2"'<>&char test + 2varchar"'<>&test + 2text test"'<>& + EEEE + FFFF + 2026-03-04T00:00:00 + + 2026-05-06T21:13:00 + [9,8,7,6] + + &^%@ + "'<>& + <&y'"> + + + + + + +-- ok for useitemtagsforcoll context id NULL +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.useitemtagsforcoll(NULL); +xml_output := gms_xmlgen.getxml(xml_cxt); +gms_output.put_line(xml_output); +gms_xmlgen.closecontext(xml_cxt); +END; +/ + + + + 1 + 1.23456 + 1.234567 + true + "'<>&char test + varchar"'<>&test + text test"'<>& + FF + ABCD + 2024-01-02T00:00:00 + + 2024-02-03T19:03:04 + {"a" : 1, "b" : 2} + + abc + "'<>& + 你好 + + + + 2 + 2.23456 + 2.234567 + false + 2"'<>&char test + 2varchar"'<>&test + 2text test"'<>& + EEEE + FFFF + 2026-03-04T00:00:00 + + 2026-05-06T21:13:00 + [9,8,7,6] + + &^%@ + "'<>& + <&y'"> + + + + + + +-- ok for closed context +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.closecontext(xml_cxt); +gms_xmlgen.useitemtagsforcoll(xml_cxt); +END; +/ +-- GMS_XMLGEN.USENULLATTRIBUTEINDICATOR +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.usenullattributeindicator(xml_cxt); +xml_output := gms_xmlgen.getxml(xml_cxt); +gms_output.put_line(xml_output); +gms_xmlgen.closecontext(xml_cxt); +END; +/ + + + + 1 + 1.23456 + 1.234567 + true + "'<>&char test + varchar"'<>&test + text test"'<>& + FF + ABCD + 2024-01-02T00:00:00 + + 2024-02-03T19:03:04 + {"a" : 1, "b" : 2} + + abc + "'<>& + 你好 + + + + 2 + 2.23456 + 2.234567 + false + 2"'<>&char test + 2varchar"'<>&test + 2text test"'<>& + EEEE + FFFF + 2026-03-04T00:00:00 + + 2026-05-06T21:13:00 + [9,8,7,6] + + &^%@ + "'<>& + <&y'"> + + + + + + + + + + + + + + + + +-- ok for parameter 2 true +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.usenullattributeindicator(xml_cxt, true); +xml_output := gms_xmlgen.getxml(xml_cxt); +gms_output.put_line(xml_output); +gms_xmlgen.closecontext(xml_cxt); +END; +/ + + + + 1 + 1.23456 + 1.234567 + true + "'<>&char test + varchar"'<>&test + text test"'<>& + FF + ABCD + 2024-01-02T00:00:00 + + 2024-02-03T19:03:04 + {"a" : 1, "b" : 2} + + abc + "'<>& + 你好 + + + + 2 + 2.23456 + 2.234567 + false + 2"'<>&char test + 2varchar"'<>&test + 2text test"'<>& + EEEE + FFFF + 2026-03-04T00:00:00 + + 2026-05-06T21:13:00 + [9,8,7,6] + + &^%@ + "'<>& + <&y'"> + + + + + + + + + + + + + + + + +-- ok for parameter 2 false, the result is the same as the true's +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.usenullattributeindicator(xml_cxt, false); +xml_output := gms_xmlgen.getxml(xml_cxt); +gms_output.put_line(xml_output); +gms_xmlgen.closecontext(xml_cxt); +END; +/ + + + + 1 + 1.23456 + 1.234567 + true + "'<>&char test + varchar"'<>&test + text test"'<>& + FF + ABCD + 2024-01-02T00:00:00 + + 2024-02-03T19:03:04 + {"a" : 1, "b" : 2} + + abc + "'<>& + 你好 + + + + 2 + 2.23456 + 2.234567 + false + 2"'<>&char test + 2varchar"'<>&test + 2text test"'<>& + EEEE + FFFF + 2026-03-04T00:00:00 + + 2026-05-06T21:13:00 + [9,8,7,6] + + &^%@ + "'<>& + <&y'"> + + + + + + + + + + + + + + + + +-- ok for usenullattributeindicator context id NULL +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.usenullattributeindicator(NULL); +xml_output := gms_xmlgen.getxml(xml_cxt); +gms_output.put_line(xml_output); +gms_xmlgen.closecontext(xml_cxt); +END; +/ + + + + 1 + 1.23456 + 1.234567 + true + "'<>&char test + varchar"'<>&test + text test"'<>& + FF + ABCD + 2024-01-02T00:00:00 + + 2024-02-03T19:03:04 + {"a" : 1, "b" : 2} + + abc + "'<>& + 你好 + + + + 2 + 2.23456 + 2.234567 + false + 2"'<>&char test + 2varchar"'<>&test + 2text test"'<>& + EEEE + FFFF + 2026-03-04T00:00:00 + + 2026-05-06T21:13:00 + [9,8,7,6] + + &^%@ + "'<>& + <&y'"> + + + + + + +-- ok for closed context +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.closecontext(xml_cxt); +gms_xmlgen.usenullattributeindicator(xml_cxt); +END; +/ +-- GMS_XMLGEN.GETNUMROWSPROCESSED +DECLARE +processed_row number; +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +processed_row:=gms_xmlgen.getnumrowsprocessed(xml_cxt); +gms_output.put_line(processed_row); +xml_output := gms_xmlgen.getxml(xml_cxt); +gms_output.put_line(xml_output); +processed_row:=gms_xmlgen.getnumrowsprocessed(xml_cxt); +gms_output.put_line(processed_row); +gms_xmlgen.closecontext(xml_cxt); +END; +/ +0 + + + + 1 + 1.23456 + 1.234567 + true + "'<>&char test + varchar"'<>&test + text test"'<>& + FF + ABCD + 2024-01-02T00:00:00 + + 2024-02-03T19:03:04 + {"a" : 1, "b" : 2} + + abc + "'<>& + 你好 + + + + 2 + 2.23456 + 2.234567 + false + 2"'<>&char test + 2varchar"'<>&test + 2text test"'<>& + EEEE + FFFF + 2026-03-04T00:00:00 + + 2026-05-06T21:13:00 + [9,8,7,6] + + &^%@ + "'<>& + <&y'"> + + + + + + +3 +-- getnumrowsprocessed with skip rows +DECLARE +processed_row number; +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.setskiprows(xml_cxt, 1); +processed_row:=gms_xmlgen.getnumrowsprocessed(xml_cxt); +gms_output.put_line(processed_row); +xml_output := gms_xmlgen.getxml(xml_cxt); +gms_output.put_line(xml_output); +processed_row:=gms_xmlgen.getnumrowsprocessed(xml_cxt); +gms_output.put_line(processed_row); +gms_xmlgen.closecontext(xml_cxt); +END; +/ +0 + + + + 2 + 2.23456 + 2.234567 + false + 2"'<>&char test + 2varchar"'<>&test + 2text test"'<>& + EEEE + FFFF + 2026-03-04T00:00:00 + + 2026-05-06T21:13:00 + [9,8,7,6] + + &^%@ + "'<>& + <&y'"> + + + + + + +2 +-- getnumrowsprocessed with max rows +DECLARE +processed_row number; +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.setmaxrows(xml_cxt, 2); +processed_row:=gms_xmlgen.getnumrowsprocessed(xml_cxt); +gms_output.put_line(processed_row); +xml_output := gms_xmlgen.getxml(xml_cxt); +gms_output.put_line(xml_output); +processed_row:=gms_xmlgen.getnumrowsprocessed(xml_cxt); +gms_output.put_line(processed_row); +gms_xmlgen.closecontext(xml_cxt); +END; +/ +0 + + + + 1 + 1.23456 + 1.234567 + true + "'<>&char test + varchar"'<>&test + text test"'<>& + FF + ABCD + 2024-01-02T00:00:00 + + 2024-02-03T19:03:04 + {"a" : 1, "b" : 2} + + abc + "'<>& + 你好 + + + + 2 + 2.23456 + 2.234567 + false + 2"'<>&char test + 2varchar"'<>&test + 2text test"'<>& + EEEE + FFFF + 2026-03-04T00:00:00 + + 2026-05-06T21:13:00 + [9,8,7,6] + + &^%@ + "'<>& + <&y'"> + + + + +2 +-- getnumrowsprocessed with skip rows && max rows +DECLARE +processed_row number; +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.setskiprows(xml_cxt, 1); +gms_xmlgen.setmaxrows(xml_cxt, 1); +processed_row:=gms_xmlgen.getnumrowsprocessed(xml_cxt); +gms_output.put_line(processed_row); +xml_output := gms_xmlgen.getxml(xml_cxt); +gms_output.put_line(xml_output); +processed_row:=gms_xmlgen.getnumrowsprocessed(xml_cxt); +gms_output.put_line(processed_row); +gms_xmlgen.closecontext(xml_cxt); +END; +/ +0 + + + + 2 + 2.23456 + 2.234567 + false + 2"'<>&char test + 2varchar"'<>&test + 2text test"'<>& + EEEE + FFFF + 2026-03-04T00:00:00 + + 2026-05-06T21:13:00 + [9,8,7,6] + + &^%@ + "'<>& + <&y'"> + + + + +1 +-- ok for getnumrowsprocessed context id NULL +DECLARE +processed_row number; +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +xml_output := gms_xmlgen.getxml(xml_cxt); +processed_row := gms_xmlgen.getnumrowsprocessed(NULL); +gms_output.put_line(processed_row); +gms_xmlgen.closecontext(xml_cxt); +END; +/ +-- ok for closed context +DECLARE +processed_row number; +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +xml_output := gms_xmlgen.getxml(xml_cxt); +gms_xmlgen.closecontext(xml_cxt); +processed_row := gms_xmlgen.getnumrowsprocessed(xml_cxt); +gms_output.put_line(processed_row); +END; +/ +-- GMS_XMLGEN.CONVERT +select GMS_XMLGEN.CONVERT('"''<>&'::varchar2); + convert +--------------------------- + "'<>& +(1 row) + +select GMS_XMLGEN.CONVERT('"''<>&'::varchar2, NULL); + convert +--------------------------- + "'<>& +(1 row) + +select GMS_XMLGEN.CONVERT('"''<>&'::varchar2, 0); + convert +--------------------------- + "'<>& +(1 row) + +select GMS_XMLGEN.CONVERT('"''<>&'::varchar2, 1); + convert +--------- + "'<>& +(1 row) + +select GMS_XMLGEN.CONVERT('"''<>&'::varchar2, 2); + convert +--------------------------- + "'<>& +(1 row) + +select GMS_XMLGEN.CONVERT('"''<>&'::varchar2, -1); + convert +--------- + +(1 row) + +select GMS_XMLGEN.CONVERT('"''<>&'::varchar2, 4294967295); + convert +--------------------------- + "'<>& +(1 row) + +select GMS_XMLGEN.CONVERT('"''<>&'::varchar2, 4294967296); + convert +--------- + +(1 row) + +select GMS_XMLGEN.CONVERT('"'<>&'::varchar2); + convert +----------------------------------------------- + &quot;&apos;&lt;&gt;&amp; +(1 row) + +select GMS_XMLGEN.CONVERT('"'<>&'::varchar2, NULL); + convert +----------------------------------------------- + &quot;&apos;&lt;&gt;&amp; +(1 row) + +select GMS_XMLGEN.CONVERT('"'<>&'::varchar2, 0); + convert +----------------------------------------------- + &quot;&apos;&lt;&gt;&amp; +(1 row) + +select GMS_XMLGEN.CONVERT('"'<>&'::varchar2, 1); + convert +--------- + "'<>& +(1 row) + +select GMS_XMLGEN.CONVERT('"'<>&'::varchar2, 2); + convert +----------------------------------------------- + &quot;&apos;&lt;&gt;&amp; +(1 row) + +-- would not convert +select GMS_XMLGEN.CONVERT('"&ApOS;<&gT;&Amp;'::varchar2, 1); + convert +--------------------------- + "&ApOS;<&gT;&Amp; +(1 row) + +select pg_typeof(GMS_XMLGEN.CONVERT('"''<>&'::varchar2, 1)); + pg_typeof +------------------- + character varying +(1 row) + +select GMS_XMLGEN.CONVERT('"''<>&'::clob); + convert +--------------------------- + "'<>& +(1 row) + +select GMS_XMLGEN.CONVERT('"''<>&'::clob, NULL); + convert +--------------------------- + "'<>& +(1 row) + +select GMS_XMLGEN.CONVERT('"''<>&'::clob, 0); + convert +--------------------------- + "'<>& +(1 row) + +select GMS_XMLGEN.CONVERT('"''<>&'::clob, 1); + convert +--------- + "'<>& +(1 row) + +select GMS_XMLGEN.CONVERT('"''<>&'::clob, 2); + convert +--------------------------- + "'<>& +(1 row) + +select GMS_XMLGEN.CONVERT('"''<>&'::clob, -1); + convert +--------- + +(1 row) + +select GMS_XMLGEN.CONVERT('"''<>&'::clob, 4294967295); + convert +--------------------------- + "'<>& +(1 row) + +select GMS_XMLGEN.CONVERT('"''<>&'::clob, 4294967296); + convert +--------- + +(1 row) + +select GMS_XMLGEN.CONVERT('"'<>&'::clob); + convert +----------------------------------------------- + &quot;&apos;&lt;&gt;&amp; +(1 row) + +select GMS_XMLGEN.CONVERT('"'<>&'::clob, NULL); + convert +----------------------------------------------- + &quot;&apos;&lt;&gt;&amp; +(1 row) + +select GMS_XMLGEN.CONVERT('"'<>&'::clob, 0); + convert +----------------------------------------------- + &quot;&apos;&lt;&gt;&amp; +(1 row) + +select GMS_XMLGEN.CONVERT('"'<>&'::clob, 1); + convert +--------- + "'<>& +(1 row) + +select GMS_XMLGEN.CONVERT('"'<>&'::clob, 2); + convert +----------------------------------------------- + &quot;&apos;&lt;&gt;&amp; +(1 row) + +-- would not convert +select GMS_XMLGEN.CONVERT('"&ApOS;<&gT;&Amp;'::clob, 1); + convert +--------------------------- + "&ApOS;<&gT;&Amp; +(1 row) + +select pg_typeof(GMS_XMLGEN.CONVERT('"''<>&'::clob, 1)); + pg_typeof +----------- + clob +(1 row) + +-- error for NULL +select GMS_XMLGEN.CONVERT(NULL, 0); +ERROR: invalid parameter +CONTEXT: referenced column: convert +select GMS_XMLGEN.CONVERT(NULL); +ERROR: invalid parameter +CONTEXT: referenced column: convert +-- compatibility tool usecases +DECLARE ctx GMS_xmlgen.ctxHandle; +BEGIN ctx := GMS_xmlgen.newContext('select * FROM t_types'); +GMS_xmlgen.closeContext(ctx); +GMS_output.put_line(ctx::text); +END; +/ +73 +DECLARE res XMLType; +BEGIN res := GMS_XMLGEN.GETXMLTYPE('123'); +EXCEPTION +WHEN OTHERS THEN NULL; +END; +/ +DECLARE res GMS_XMLGEN.ctxHandle; +BEGIN res := GMS_XMLGEN.NEWCONTEXTFROMHIERARCHY('123'); +EXCEPTION +WHEN OTHERS THEN NULL; +END; +/ +DECLARE d varchar2(100); +a varchar2(100); +BEGIN d := GMS_XMLGEN.CONVERT(a); +EXCEPTION +WHEN OTHERS THEN NULL; +END; +/ +DECLARE d number; +a GMS_XMLGEN.ctxHandle; +BEGIN d := GMS_XMLGEN.GETNUMROWSPROCESSED(a); +EXCEPTION +WHEN OTHERS THEN NULL; +END; +/ +DECLARE a GMS_XMLGEN.ctxHandle; +b clob; +BEGIN b := GMS_XMLGEN.GETXML(a); +EXCEPTION +WHEN OTHERS THEN NULL; +END; +/ +DECLARE CTX GMS_XMLGEN.CTXHANDLE; +BEGIN CTX := GMS_XMLGEN.NEWCONTEXT('select * FROM t_types'); +EXCEPTION +WHEN OTHERS THEN NULL; +END; +/ +DECLARE CTX GMS_XMLGEN.CTXHANDLE; +BEGIN GMS_XMLGEN.RESTARTQUERY(CTX); +EXCEPTION +WHEN OTHERS THEN NULL; +END; +/ +DECLARE CTX GMS_XMLGEN.CTXHANDLE; +BEGIN CTX := GMS_XMLGEN.NEWCONTEXT('select * FROM t_types'); +GMS_XMLGEN.SETCONVERTSPECIALCHARS(CTX, false); +END; +/ +DECLARE CTX GMS_XMLGEN.CTXHANDLE; +BEGIN GMS_XMLGEN.SETMAXROWS(CTX, 2); +EXCEPTION +WHEN OTHERS THEN NULL; +END; +/ +DECLARE CTX GMS_XMLGEN.CTXHANDLE; +BEGIN CTX := GMS_XMLGEN.NEWCONTEXT('select * FROM t_types'); +GMS_XMLGEN.SETNULLHANDLING(CTX, 1); +END; +/ +DECLARE CTX GMS_XMLGEN.CTXHANDLE; +BEGIN CTX := GMS_XMLGEN.NEWCONTEXT('select * FROM t_types'); +GMS_XMLGEN.SETROWSETTAG(CTX, 'srst'); +END; +/ +DECLARE CTX GMS_XMLGEN.CTXHANDLE; +BEGIN CTX := GMS_XMLGEN.NEWCONTEXT('select * FROM t_types'); +GMS_XMLGEN.SETROWTAG(CTX, 'srst'); +END; +/ +DECLARE CTX GMS_XMLGEN.CTXHANDLE; +BEGIN GMS_XMLGEN.SETSKIPROWS(CTX, 5); +EXCEPTION +WHEN OTHERS THEN NULL; +END; +/ +DECLARE CTX GMS_XMLGEN.CTXHANDLE; +BEGIN GMS_XMLGEN.USEITEMTAGSFORCOLL(CTX); +EXCEPTION +WHEN OTHERS THEN NULL; +END; +/ +DECLARE CTX GMS_XMLGEN.CTXHANDLE; +BEGIN CTX := GMS_XMLGEN.NEWCONTEXT('select * FROM t_types'); +GMS_XMLGEN.USENULLATTRIBUTEINDICATOR(CTX, false); +END; +/ +reset search_path; +drop schema gms_xmlgen_test cascade; +NOTICE: drop cascades to table gms_xmlgen_test.t_types diff --git a/contrib/gms_xmlgen/gms_xmlgen--1.0.sql b/contrib/gms_xmlgen/gms_xmlgen--1.0.sql new file mode 100644 index 000000000..18e94dfd7 --- /dev/null +++ b/contrib/gms_xmlgen/gms_xmlgen--1.0.sql @@ -0,0 +1,192 @@ +/* contrib/gms_xmlgen/gms_xmlgen--1.0.sql */ + +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "CREATE EXTENSION gms_xmlgen" to load this file. \quit + +CREATE SCHEMA gms_xmlgen; +GRANT USAGE ON SCHEMA gms_xmlgen TO PUBLIC; + +-- create fake type gms_xmlgen.ctxhandle +create domain gms_xmlgen.ctxhandle as number; + +-- gms_xmlgen.closecontext +CREATE OR REPLACE FUNCTION gms_xmlgen.close_context(ctx IN gms_xmlgen.ctxhandle) +RETURNS void +AS 'MODULE_PATHNAME', 'close_context' +LANGUAGE C STRICT IMMUTABLE; + +CREATE OR REPLACE PROCEDURE gms_xmlgen.closecontext(ctx IN gms_xmlgen.ctxhandle) +AS +BEGIN + gms_xmlgen.close_context(ctx); +END; + +-- gms_xmlgen.convert +CREATE OR REPLACE FUNCTION gms_xmlgen.convert(xmlData IN VARCHAR2, flag IN NUMBER := 0) +RETURNS VARCHAR2 PACKAGE +AS 'MODULE_PATHNAME', 'convert_xml' +LANGUAGE C IMMUTABLE; + +CREATE OR REPLACE FUNCTION gms_xmlgen.convert(xmlData IN CLOB, flag IN NUMBER := 0) +RETURNS CLOB PACKAGE +AS 'MODULE_PATHNAME', 'convert_clob' +LANGUAGE C IMMUTABLE; + +-- gms_xmlgen.getnumrowsprocessed +CREATE OR REPLACE FUNCTION gms_xmlgen.getnumrowsprocessed(ctx IN gms_xmlgen.ctxhandle) +RETURNS NUMBER +AS 'MODULE_PATHNAME', 'get_num_rows_processed' +LANGUAGE C STRICT VOLATILE; + +-- gms_xmlgen.getxml +CREATE OR REPLACE FUNCTION gms_xmlgen.getxml(sqlQuery IN VARCHAR2, dtdOrSchema IN NUMBER := 0) +RETURNS CLOB PACKAGE +AS 'MODULE_PATHNAME', 'get_xml_by_query' +LANGUAGE C VOLATILE; + +CREATE OR REPLACE FUNCTION gms_xmlgen.getxml(ctx IN gms_xmlgen.ctxhandle, dtdOrSchema IN NUMBER := 0) +RETURNS CLOB PACKAGE +AS 'MODULE_PATHNAME', 'get_xml_by_ctx_id' +LANGUAGE C VOLATILE; + +CREATE OR REPLACE PROCEDURE gms_xmlgen.getxml(ctx IN gms_xmlgen.ctxhandle, tmpclob INOUT CLOB, dtdOrSchema IN NUMBER := 0) +PACKAGE +AS +BEGIN + tmpclob := gms_xmlgen.getxml(ctx, dtdOrSchema); +END; + +-- gms_xmlgen.getxmltype +CREATE OR REPLACE FUNCTION gms_xmlgen.getxmltype(ctx IN gms_xmlgen.ctxhandle, dtdOrSchema IN NUMBER := 0) + RETURNS xmltype PACKAGE +AS $$ +select xmltype(gms_xmlgen.getxml(ctx, dtdOrSchema))::xmltype; +$$ +LANGUAGE SQL VOLATILE; + +CREATE OR REPLACE FUNCTION gms_xmlgen.getxmltype(sqlQuery IN VARCHAR2, dtdOrSchema IN NUMBER := 0) + RETURNS xmltype PACKAGE +AS $$ +select xmltype(gms_xmlgen.getxml(sqlQuery, dtdOrSchema))::xmltype; +$$ +LANGUAGE SQL VOLATILE; + +-- gms_xmlgen.newcontext +CREATE OR REPLACE FUNCTION gms_xmlgen.newcontext(queryString IN VARCHAR2) +RETURNS gms_xmlgen.ctxhandle PACKAGE +AS 'MODULE_PATHNAME', 'new_context_by_query' +LANGUAGE C VOLATILE; + +CREATE OR REPLACE FUNCTION gms_xmlgen.newcontext(queryString IN SYS_REFCURSOR) +RETURNS gms_xmlgen.ctxhandle PACKAGE +AS 'MODULE_PATHNAME', 'new_context_by_cursor' +LANGUAGE C VOLATILE; + +-- gms_xmlgen.newcontextfromhierarchy +CREATE OR REPLACE FUNCTION gms_xmlgen.newcontextfromhierarchy(queryString IN VARCHAR2) +RETURNS gms_xmlgen.ctxhandle +AS 'MODULE_PATHNAME', 'new_context_from_hierarchy' +LANGUAGE C VOLATILE; + +-- gms_xmlgen.restartquery +CREATE OR REPLACE FUNCTION gms_xmlgen.restart_query(ctx IN gms_xmlgen.ctxhandle) +RETURNS gms_xmlgen.ctxhandle +AS 'MODULE_PATHNAME', 'restart_query' +LANGUAGE C STRICT VOLATILE; + +CREATE OR REPLACE PROCEDURE gms_xmlgen.restartquery(ctx IN gms_xmlgen.ctxhandle) +AS +BEGIN + gms_xmlgen.restart_query(ctx); +END; + +-- gms_xmlgen.setconvertspecialchars +CREATE OR REPLACE FUNCTION gms_xmlgen.set_convert_special_chars(ctx IN gms_xmlgen.ctxhandle, is_convert IN boolean) +RETURNS void +AS 'MODULE_PATHNAME', 'set_convert_special_chars' +LANGUAGE C STRICT IMMUTABLE; + +CREATE OR REPLACE PROCEDURE gms_xmlgen.setconvertspecialchars(ctx IN gms_xmlgen.ctxhandle, is_convert IN boolean) +AS +BEGIN + gms_xmlgen.set_convert_special_chars(ctx, is_convert); +END; + +-- gms_xmlgen.setmaxrows +CREATE OR REPLACE FUNCTION gms_xmlgen.set_max_rows(ctx IN gms_xmlgen.ctxhandle, maxrows IN NUMBER) +RETURNS void +AS 'MODULE_PATHNAME', 'set_max_rows' +LANGUAGE C STRICT IMMUTABLE; + +CREATE OR REPLACE PROCEDURE gms_xmlgen.setmaxrows(ctx IN gms_xmlgen.ctxhandle, maxrows IN NUMBER) +AS +BEGIN + gms_xmlgen.set_max_rows(ctx, maxrows); +END; + +-- gms_xmlgen.setnullhandling +CREATE OR REPLACE FUNCTION gms_xmlgen.set_null_handling(ctx IN gms_xmlgen.ctxhandle, flag IN NUMBER) +RETURNS void +AS 'MODULE_PATHNAME', 'set_null_handling' +LANGUAGE C STRICT IMMUTABLE; + +CREATE OR REPLACE PROCEDURE gms_xmlgen.setnullhandling(ctx IN gms_xmlgen.ctxhandle, flag IN NUMBER) +AS +BEGIN + gms_xmlgen.set_null_handling(ctx, flag); +END; + +-- gms_xmlgen.setrowsettag +CREATE OR REPLACE FUNCTION gms_xmlgen.set_row_set_tag(ctx IN gms_xmlgen.ctxhandle, rowSetTagName IN VARCHAR2) +RETURNS void +AS 'MODULE_PATHNAME', 'set_row_set_tag' +LANGUAGE C IMMUTABLE; + +CREATE OR REPLACE PROCEDURE gms_xmlgen.setrowsettag(ctx IN gms_xmlgen.ctxhandle, rowSetTagName IN VARCHAR2) +AS +BEGIN + gms_xmlgen.set_row_set_tag(ctx, rowSetTagName); +END; + +-- gms_xmlgen.setrowtag +CREATE OR REPLACE FUNCTION gms_xmlgen.set_row_tag(ctx IN gms_xmlgen.ctxhandle, rowTagName IN VARCHAR2) +RETURNS void +AS 'MODULE_PATHNAME', 'set_row_tag' +LANGUAGE C IMMUTABLE; + +CREATE OR REPLACE PROCEDURE gms_xmlgen.setrowtag(ctx IN gms_xmlgen.ctxhandle, rowTagName IN VARCHAR2) +AS +BEGIN + gms_xmlgen.set_row_tag(ctx, rowTagName); +END; + +-- gms_xmlgen.setskiprows +CREATE OR REPLACE FUNCTION gms_xmlgen.set_skip_rows(ctx IN gms_xmlgen.ctxhandle, skipRows IN NUMBER) +RETURNS void +AS 'MODULE_PATHNAME', 'set_skip_rows' +LANGUAGE C STRICT IMMUTABLE; + +CREATE OR REPLACE PROCEDURE gms_xmlgen.setskiprows(ctx IN gms_xmlgen.ctxhandle, skipRows IN NUMBER) +AS +BEGIN + gms_xmlgen.set_skip_rows(ctx, skipRows); +END; + +-- gms_xmlgen.useitemtagsforcoll +CREATE OR REPLACE FUNCTION gms_xmlgen.use_item_tags_for_coll(ctx IN gms_xmlgen.ctxhandle) +RETURNS void +AS 'MODULE_PATHNAME', 'use_item_tags_for_coll' +LANGUAGE C STRICT IMMUTABLE; + +CREATE OR REPLACE PROCEDURE gms_xmlgen.useitemtagsforcoll(ctx IN gms_xmlgen.ctxhandle) +AS +BEGIN + gms_xmlgen.use_item_tags_for_coll(ctx); +END; + +-- gms_xmlgen.usenullattributeindicator +CREATE OR REPLACE PROCEDURE gms_xmlgen.usenullattributeindicator(ctx IN gms_xmlgen.ctxhandle, attrind IN BOOLEAN := TRUE) +AS +BEGIN + gms_xmlgen.set_null_handling(ctx, 1); +END; diff --git a/contrib/gms_xmlgen/gms_xmlgen.control b/contrib/gms_xmlgen/gms_xmlgen.control new file mode 100644 index 000000000..dc38eee26 --- /dev/null +++ b/contrib/gms_xmlgen/gms_xmlgen.control @@ -0,0 +1,5 @@ +# gms_xmlgen extension +comment = 'Converting the results of a SQL query to a canonical XML format' +default_version = '1.0' +module_pathname = '$libdir/gms_xmlgen' +relocatable = true diff --git a/contrib/gms_xmlgen/gms_xmlgen.cpp b/contrib/gms_xmlgen/gms_xmlgen.cpp new file mode 100644 index 000000000..4125180e4 --- /dev/null +++ b/contrib/gms_xmlgen/gms_xmlgen.cpp @@ -0,0 +1,1381 @@ +#include "postgres.h" +#include "knl/knl_variable.h" +#include "fmgr.h" +#include "funcapi.h" +#include "libpq/pqformat.h" +#include "utils/builtins.h" +#include "utils/lsyscache.h" +#include "utils/int16.h" +#include "utils/int8.h" +#include "utils/memutils.h" +#include "utils/numeric.h" +#include "utils/numeric_gs.h" +#include "utils/portal.h" +#include "utils/xml.h" +#include "executor/spi.h" +#include "tcop/tcopprot.h" +#include "commands/extension.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "gms_xmlgen.h" + +PG_MODULE_MAGIC; + +PG_FUNCTION_INFO_V1(ctxhandle_in); +PG_FUNCTION_INFO_V1(ctxhandle_out); +PG_FUNCTION_INFO_V1(close_context); +PG_FUNCTION_INFO_V1(convert_xml); +PG_FUNCTION_INFO_V1(convert_clob); +PG_FUNCTION_INFO_V1(get_num_rows_processed); +PG_FUNCTION_INFO_V1(get_xml_by_ctx_id); +PG_FUNCTION_INFO_V1(get_xml_by_query); +PG_FUNCTION_INFO_V1(new_context_by_query); +PG_FUNCTION_INFO_V1(new_context_by_cursor); +PG_FUNCTION_INFO_V1(new_context_from_hierarchy); +PG_FUNCTION_INFO_V1(restart_query); +PG_FUNCTION_INFO_V1(set_convert_special_chars); +PG_FUNCTION_INFO_V1(set_max_rows); +PG_FUNCTION_INFO_V1(set_null_handling); +PG_FUNCTION_INFO_V1(set_row_set_tag); +PG_FUNCTION_INFO_V1(set_row_tag); +PG_FUNCTION_INFO_V1(set_skip_rows); +PG_FUNCTION_INFO_V1(use_item_tags_for_coll); + +static uint32 g_xmlgen_extension_id; + +#define TOP_CONTEXT ((XMLGenTopContext *)(u_sess->attr.attr_common.extension_session_vars_array[g_xmlgen_extension_id])) + +void set_extension_index(uint32 index) +{ + g_xmlgen_extension_id = index; +} + +void init_session_vars(void) +{ + RepallocSessionVarsArrayIfNecessary(); + + XMLGenTopContext *g_xmlgen_mem_ctx = + (XMLGenTopContext *)MemoryContextAllocZero(u_sess->self_mem_cxt, sizeof(XMLGenTopContext)); + + g_xmlgen_mem_ctx->memctx = u_sess->self_mem_cxt; + g_xmlgen_mem_ctx->xmlgen_context_list = NIL; + g_xmlgen_mem_ctx->xmlgen_context_id = 0; + + u_sess->attr.attr_common.extension_session_vars_array[g_xmlgen_extension_id] = g_xmlgen_mem_ctx; +} + +/** + * get XMLGenContext by ctx_id + * @param {int64} ctx_id + * @return {XMLGenContext} ctx + */ +static XMLGenContext *get_xmlgen_context(int64 ctx_id) +{ + if (TOP_CONTEXT->xmlgen_context_list == NIL) { + return NULL; + } + + ListCell *lc = NULL; + foreach (lc, TOP_CONTEXT->xmlgen_context_list) { + XMLGenContext *ctx = (XMLGenContext *)lfirst(lc); + if (ctx->ctx_id == ctx_id) { + return ctx; + } + } + + return NULL; +} + +/** + * free XMLGenContext + * @param {XMLGenContext*} ctx - XMLGenContext pointer + * @return {void} + */ +static void free_xmlgen_context(XMLGenContext *ctx) +{ + if (ctx->memctx != NULL) { + MemoryContextDelete(ctx->memctx); + } + + MemoryContext oldcontext = MemoryContextSwitchTo(TOP_CONTEXT->memctx); + + TOP_CONTEXT->xmlgen_context_list = list_delete(TOP_CONTEXT->xmlgen_context_list, (void *)ctx); + + MemoryContextSwitchTo(oldcontext); + MemoryContextReset(ctx->memctx); + pfree_ext(ctx); +} + +/** + * unescape XML data + * @param {const char *} str - escaped string data + * @return {char *} result - unescaped string data + */ +static char *convert_decode(const char *str) +{ + StringInfoData buf; + const char *p = NULL; + int charlen = 0; + + initStringInfo(&buf); + p = str; + while (*p) { + if (*p == '&') { + if (strncmp(p, "<", 4) == 0) { + appendStringInfoString(&buf, "<"); + charlen = 4; + } else if (strncmp(p, ">", 4) == 0) { + appendStringInfoString(&buf, ">"); + charlen = 4; + } else if (strncmp(p, """, 6) == 0) { + appendStringInfoString(&buf, "\""); + charlen = 6; + } else if (strncmp(p, "'", 6) == 0) { + appendStringInfoString(&buf, "'"); + charlen = 6; + } else if (strncmp(p, "&", 5) == 0) { + appendStringInfoString(&buf, "&"); + charlen = 5; + } else { + appendStringInfoString(&buf, "&"); + charlen = 1; + } + } else { + charlen = pg_mblen(p); + for (int i = 0; i < charlen; i++) { + appendStringInfoCharMacro(&buf, p[i]); + } + } + p += charlen; + } + return buf.data; +} + +/** + * escape XML data + * @param {const char *} str - unescaped string data + * @return {char *} result - escaped string data + */ +static char *convert_encode(const char *str) +{ + StringInfoData buf; + const char *p = NULL; + int charlen = 0; + + initStringInfo(&buf); + p = str; + while (*p) { + charlen = pg_mblen(p); + switch (*p) { + case '&': + appendStringInfoString(&buf, "&"); + break; + case '<': + appendStringInfoString(&buf, "<"); + break; + case '>': + appendStringInfoString(&buf, ">"); + break; + case '"': + appendStringInfoString(&buf, """); + break; + case '\'': + appendStringInfoString(&buf, "'"); + break; + default: { + for (int i = 0; i < charlen; i++) { + appendStringInfoCharMacro(&buf, p[i]); + } + break; + } + } + p += charlen; + } + return buf.data; +} + +/** + * map date value to xml value + * @param {Datum} value - bytea datum value + * @return {char *} result - xml value + */ +static char *map_date_value_to_xml(Datum value) +{ + DateADT date; + struct pg_tm tm; + char buf[MAXDATELEN + 1]; + + date = DatumGetDateADT(value); + if (DATE_NOT_FINITE(date)) { + ereport(ERROR, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("date out of range"), + errdetail("XML does not support infinite date values."))); + } + j2date(date + POSTGRES_EPOCH_JDATE, &(tm.tm_year), &(tm.tm_mon), &(tm.tm_mday)); + EncodeDateOnly(&tm, USE_XSD_DATES, buf); + + return pstrdup(buf); +} + +/** + * map timestamp value to xml value + * @param {Datum} value - bytea datum value + * @return {char *} result - xml value + */ +static char *map_timestamp_value_to_xml(Datum value, bool is_tz) +{ + TimestampTz timestamp; + struct pg_tm tm; + int tz; + fsec_t fsec; + const char *tzn = NULL; + char buf[MAXDATELEN + 1]; + + timestamp = DatumGetTimestamp(value); + + if (TIMESTAMP_NOT_FINITE(timestamp)) { + ereport(ERROR, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range"), + errdetail("XML does not support infinite timestamp values."))); + } else if (timestamp2tm(timestamp, is_tz ? &tz : NULL, &tm, &fsec, is_tz ? &tzn : NULL, NULL) == 0) { + EncodeDateTime(&tm, fsec, is_tz, is_tz ? tz : 0, is_tz ? tzn : NULL, USE_XSD_DATES, buf); + } else { + ereport(ERROR, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range"))); + } + + return pstrdup(buf); +} + +/** + * map bytea value to xml value + * @param {Datum} value - bytea datum value + * @return {char *} result - xml value + */ +static char *map_bytea_value_to_xml(Datum value) +{ + bytea *bstr = DatumGetByteaPP(value); + volatile xmlBufferPtr buf = NULL; + volatile xmlTextWriterPtr writer = NULL; + char *result = NULL; + + PG_TRY(); + { + buf = xmlBufferCreate(); + if (buf == NULL) { + ereport(ERROR, (errcode(ERRCODE_OUT_OF_MEMORY), errmsg("could not allocate xmlBuffer"))); + } + writer = xmlNewTextWriterMemory(buf, 0); + if (writer == NULL) { + xmlBufferFree(buf); + ereport(ERROR, (errcode(ERRCODE_OUT_OF_MEMORY), errmsg("could not allocate xmlTextWriter"))); + } + if (u_sess->attr.attr_common.xmlbinary == XMLBINARY_BASE64) { + xmlTextWriterWriteBase64(writer, VARDATA_ANY(bstr), 0, VARSIZE_ANY_EXHDR(bstr)); + } else { + xmlTextWriterWriteBinHex(writer, VARDATA_ANY(bstr), 0, VARSIZE_ANY_EXHDR(bstr)); + } + /* we MUST do this now to flush data out to the buffer */ + xmlFreeTextWriter(writer); + writer = NULL; + + result = pstrdup((const char *)xmlBufferContent(buf)); + } + PG_CATCH(); + { + if (writer) { + xmlFreeTextWriter(writer); + } + if (buf) { + xmlBufferFree(buf); + } + PG_RE_THROW(); + } + PG_END_TRY(); + + xmlBufferFree(buf); + + return result; +} + +/** + * map array value to xml value + * @param {Datum} value - array datum value + * @param {bool} xml_escape_strings - is convert special chars + * @param {char *} array_tag_suffix - array tag suffix + * @param {int} indent_level - indentation level + * @return {char *} result - xml value + */ +char *map_array_value_to_xml(Datum value, bool xml_escape_strings, char *array_tag_suffix, int indent_level) +{ + ArrayType *array = NULL; + Oid elmtype; + int16 elmlen; + bool elmbyval = false; + char elmalign; + int num_elems; + Datum *elem_values = NULL; + bool *elem_nulls = NULL; + StringInfoData buf; + int i; + + array = DatumGetArrayTypeP(value); + elmtype = ARR_ELEMTYPE(array); + get_typlenbyvalalign(elmtype, &elmlen, &elmbyval, &elmalign); + const char *type_name = get_typename(elmtype); + const char *item_suffix = array_tag_suffix == NULL ? "" : array_tag_suffix; + + deconstruct_array(array, elmtype, elmlen, elmbyval, elmalign, &elem_values, &elem_nulls, &num_elems); + + initStringInfo(&buf); + + for (i = 0; i < num_elems; i++) { + if (elem_nulls[i]) + continue; + appendStringInfoString(&buf, "\n"); + appendStringInfoSpaces(&buf, (indent_level + 1) * SPACE_PER_INDENTATION); + appendStringInfo(&buf, "<%s%s>", type_name, item_suffix); + appendStringInfoString(&buf, map_sql_value_to_xml(elem_values[i], elmtype, xml_escape_strings, array_tag_suffix, + indent_level + 1)); + appendStringInfo(&buf, "", type_name, item_suffix); + } + appendStringInfoString(&buf, "\n"); + appendStringInfoSpaces(&buf, indent_level * SPACE_PER_INDENTATION); + pfree_ext(elem_values); + pfree_ext(elem_nulls); + + return buf.data; +} + +/** + * map sql column value to xml value + * @param {Datum} value - column value + * @param {Oid} type - column type + * @param {bool} xml_escape_strings - is convert special chars + * @param {char *} array_tag_suffix - array tag suffix + * @param {int} indent_level - indentation level + * @return {char *} result - xml value + */ +static char *map_sql_value_to_xml(Datum value, Oid type, bool xml_escape_strings, char *array_tag_suffix, + int indent_level) +{ + if (type_is_array_domain(type)) { + return map_array_value_to_xml(value, xml_escape_strings, array_tag_suffix, indent_level); + } else { + switch (type) { + case BOOLOID: + return (char *)(DatumGetBool(value) ? "true" : "false"); + case DATEOID: + return map_date_value_to_xml(value); + case TIMESTAMPOID: + return map_timestamp_value_to_xml(value, false); + case TIMESTAMPTZOID: + return map_timestamp_value_to_xml(value, true); + case BYTEAOID: + return map_bytea_value_to_xml(value); + default: { + Oid typeOut; + bool isvarlena = false; + char *str = NULL; + + getTypeOutputInfo(type, &typeOut, &isvarlena); + str = OidOutputFunctionCall(typeOut, value); + + if (type == XMLOID || !xml_escape_strings) { + return str; + } + + return convert_encode(str); + } + } + } +} + +/** + * convert datum to int + * @param {Datum} datum + * @return {Oid} type - datum type + */ +static int convert_datum_to_int(Datum datum, Oid type) +{ + Oid type_out; + bool is_varlena = false; + getTypeOutputInfo(type, &type_out, &is_varlena); + char *str = OidOutputFunctionCall(type_out, datum); + int result = 0; + return sscanf_s(str, "%d", &result) == 1 ? result : -1; +} + +/** + * add node to hierarchy xml + * @param {xmlNodePtr} pre_node + * @param {xmlNodePtr} cur_node + * @param {int} pre_level + * @param {int} cur_level + * @return {xmlNodePtr} return cur_node, or NULL otherwise + */ +static xmlNodePtr add_node_to_hierarchy_xml(xmlNodePtr pre_node, xmlNodePtr cur_node, int pre_level, int cur_level) +{ + if (pre_node == NULL) { + return NULL; + } + xmlNodePtr pre_node_inner_pointer = pre_node; + int pre_level_inner = pre_level; + if (cur_level > pre_level_inner + 1) { + return NULL; + } + int64 i = MAX_DEPTH; + while (i > 0) { + if (cur_level == pre_level_inner + 1) { + xmlAddChild(pre_node_inner_pointer, cur_node); + return cur_node; + } + if (pre_node_inner_pointer->parent == NULL) { + return NULL; + } + pre_node_inner_pointer = pre_node_inner_pointer->parent; + pre_level_inner -= 1; + i--; + } + return NULL; +} + +/** + * convert hierarchy sql row to xml element + * @param {int64} count_rows + * @return {xmlDocPtr} result + */ +static xmlDocPtr SPI_hierarchy_sql_row_to_xml_element(int64 count_rows) +{ + xmlDocPtr result = xmlNewDoc(BAD_CAST "1.0"); + bool is_first_node = true; + bool is_null = false; + int pre_level = -1; + xmlNodePtr pre_node = NULL; + int cur_level = -1; + xmlNodePtr cur_node = NULL; + Datum level_datum = 0; + + for (int64 i = 0; i < count_rows; i++) { + level_datum = SPI_getbinval(SPI_tuptable->vals[i], SPI_tuptable->tupdesc, 1, &is_null); + if (is_null) { + if (result != NULL) { + xmlFreeDoc(result); + } + ereport(ERROR, (errcode(ERRCODE_DATA_EXCEPTION), errmsg("invalid hierarchy query result"))); + } + cur_level = convert_datum_to_int(level_datum, SPI_gettypeid(SPI_tuptable->tupdesc, 1)); + if (cur_level < 0) { + if (result != NULL) { + xmlFreeDoc(result); + } + ereport(ERROR, (errcode(ERRCODE_DATA_EXCEPTION), errmsg("invalid hierarchy query level"))); + } + + Datum xml_node = SPI_getbinval(SPI_tuptable->vals[i], SPI_tuptable->tupdesc, 2, &is_null); + if (is_null) { + char *xml_name = map_sql_identifier_to_xml_name(SPI_fname(SPI_tuptable->tupdesc, 2), true, false); + cur_node = xmlNewNode(0, BAD_CAST xml_name); + } else { + char *xml_value = map_sql_value_to_xml(xml_node, SPI_gettypeid(SPI_tuptable->tupdesc, 2), false); + xmlDocPtr doc_from_xml_value = xmlParseMemory(xml_value, (int)(strlen(xml_value))); + cur_node = xmlCopyNode(xmlDocGetRootElement(doc_from_xml_value), 1); + xmlFreeDoc(doc_from_xml_value); + } + if (is_first_node) { + xmlNodePtr old_node = xmlDocSetRootElement(result, cur_node); + xmlFreeNode(old_node); + is_first_node = false; + } else { + xmlNodePtr cur_node_tmp = add_node_to_hierarchy_xml(pre_node, cur_node, pre_level, cur_level); + if (cur_node_tmp == NULL) { + xmlFreeNode(cur_node); + xmlFreeDoc(result); + ereport(ERROR, (errcode(ERRCODE_DATA_EXCEPTION), errmsg("invalid hierarchy query node"))); + } + cur_node = cur_node_tmp; + } + pre_node = cur_node; + pre_level = cur_level; + } + return result; +} + +/** + * convert hierarchy sql row to string + * @param {int64} count_rows + * @param {StringInfo} result + * @param {char *} row_set_tag - row-set tag name + * @return {void} + */ +static void SPI_hierarchy_sql_row_to_string(int64 count_rows, StringInfo result, char *row_set_tag) +{ + xmlDocPtr xml_doc = SPI_hierarchy_sql_row_to_xml_element(count_rows); + if (row_set_tag != NULL) { + xmlNodePtr cur_node = xmlNewNode(0, BAD_CAST row_set_tag); + xmlNodePtr old_node = xmlDocSetRootElement(xml_doc, cur_node); + xmlAddChild(cur_node, old_node); + } + xmlChar *out_buf = NULL; + int out_len = 0; + xmlDocDumpFormatMemoryEnc(xml_doc, &out_buf, &out_len, "utf-8", 1); + appendStringInfo(result, "%s", out_buf); + xmlFree(out_buf); + xmlFreeDoc(xml_doc); +} + +/** + * handle query to xml hierarchy + * @param {XMLGenContext *} ctx + * @return {StringInfo} result + */ +static StringInfo query_to_xml_hierarchy(XMLGenContext *ctx) +{ + StringInfo result = makeStringInfo(); + const char *query = (const char *)ctx->query_string; + if (SPI_connect() != SPI_OK_CONNECT) { + SPI_finish(); + ereport(ERROR, (errcode(ERRCODE_SPI_CONNECTION_FAILURE), errmsg("SPI_connect failed"))); + } + + if (SPI_execute(query, true, 0) != SPI_OK_SELECT) { + SPI_finish(); + ereport(ERROR, (errcode(ERRCODE_DATA_EXCEPTION), errmsg("fail to execute query"))); + } + + if (SPI_tuptable->tupdesc->natts != 2 || + (SPI_gettypeid(SPI_tuptable->tupdesc, 1) != NUMERICOID && SPI_gettypeid(SPI_tuptable->tupdesc, 1) != INT4OID) || + (SPI_gettypeid(SPI_tuptable->tupdesc, 2) != XMLOID && + strcasecmp(SPI_gettype(SPI_tuptable->tupdesc, 2), XMLTYPE_STR) != 0)) { + ereport(ERROR, (errcode(ERRCODE_DATA_EXCEPTION), errmsg("invalid query result"))); + } + + int64 count_rows = (int64)SPI_processed; + SPI_hierarchy_sql_row_to_string(count_rows, result, + ctx->is_hierarchy_set_row_set_tag ? ctx->row_set_tag_name : NULL); + ctx->processed_rows = count_rows; + SPI_finish(); + return result; +} + +/** + * generate xml doc root element start + * @param {StringInfo} result + * @param {const char*} eltname - root element name + * @param {int64} null_flag + * @return {void} + */ +static void xml_root_element_start(StringInfo result, const char *eltname, int64 null_flag) +{ + if (eltname == NULL) { + return; + } + appendStringInfo(result, XML_HEADER); + appendStringInfo(result, "<%s", eltname); + if (null_flag == NULL_FLAG_NULL_ATTR) { + appendStringInfo(result, " %s", XML_XSI_ATTR); + } + + appendStringInfo(result, ">\n"); +} + +/** + * generate xml doc root element end + * @param {StringInfo} result + * @param {const char*} eltname - root element name + * @return {void} + */ +static void xml_root_element_end(StringInfo result, const char *eltname) +{ + if (eltname == NULL) { + return; + } + appendStringInfo(result, "\n", eltname); +} + +/** + * convert sql row to xml elemeny by SPI + * @param {int64} rownum - convert data from this rownum + * @param {StringInfo} result + * @param {int64} null_flag - how to display null element + * @param {char *} row_tag - row tag name + * @param {bool} is_convert_special_chars - is convert special chars + * @param {char *} item_tag - tag suffix for array item + * @param {int64} indentation_level - indentations before data + * @return {void} + */ +static void SPI_sql_row_to_xml_element(int64 rownum, StringInfo result, int64 null_flag, char *row_tag, + bool is_convert_special_chars, char *item_tag, int64 indentation_level) +{ + if (row_tag != NULL) { + if (result->len == 0) { + appendStringInfo(result, XML_HEADER); + appendStringInfo(result, "<%s", row_tag); + if (null_flag == NULL_FLAG_NULL_ATTR) { + appendStringInfo(result, " %s", XML_XSI_ATTR); + } + appendStringInfo(result, ">\n"); + } else { + appendStringInfoSpaces(result, indentation_level * SPACE_PER_INDENTATION); + appendStringInfo(result, "<%s>\n", row_tag); + } + } + + for (int i = 1; i <= SPI_tuptable->tupdesc->natts; i++) { + char *colname = map_sql_identifier_to_xml_name(SPI_fname(SPI_tuptable->tupdesc, i), true, false); + bool isnull = false; + Datum colval = SPI_getbinval(SPI_tuptable->vals[rownum], SPI_tuptable->tupdesc, i, &isnull); + + if (isnull) { + if (colname == NULL) { + continue; + } + if (null_flag == NULL_FLAG_NULL_ATTR) { + appendStringInfoSpaces(result, indentation_level * SPACE_PER_INDENTATION); + appendStringInfo(result, "%s%s<%s%s xsi:nil=\"true\"/>\n", result->len == 0 ? XML_HEADER : "", + row_tag == NULL ? "" : " ", result->len == 0 ? XML_XSI_ATTR : "", colname); + } else if (null_flag == NULL_FLAG_EMPTY_TAG) { + appendStringInfoSpaces(result, indentation_level * SPACE_PER_INDENTATION); + appendStringInfo(result, "%s%s<%s/>\n", result->len == 0 ? XML_HEADER : "", row_tag == NULL ? "" : " ", + colname); + } + } else if (colname != NULL) { + appendStringInfoSpaces(result, indentation_level * SPACE_PER_INDENTATION); + appendStringInfo(result, "%s%s<%s%s>%s\n", result->len == 0 ? XML_HEADER : "", + row_tag == NULL ? "" : " ", colname, + result->len == 0 && null_flag == NULL_FLAG_NULL_ATTR ? XML_XSI_ATTR : "", + map_sql_value_to_xml(colval, SPI_gettypeid(SPI_tuptable->tupdesc, i), + is_convert_special_chars, item_tag, indentation_level + 1), + colname); + } + } + + if (row_tag != NULL) { + appendStringInfoSpaces(result, indentation_level * SPACE_PER_INDENTATION); + appendStringInfo(result, "\n", row_tag); + } +} + +/** + * check the xml is valid, fail if has no root element or has multiple ones + * @param {const XMLGenContext *} ctx - xmlgen contxt pointer + * @param {int64} rows - rows in xml + * @param {int64} columns - columns in a row + * @return {void} + */ +static void check_xml_valid(const XMLGenContext *ctx, int64 rows, int64 columns) +{ + if (ctx->row_set_tag_name == NULL && (rows != 1 || (ctx->row_tag_name == NULL && columns != 1))) { + ereport(ERROR, (errcode(ERRCODE_DATA_EXCEPTION), errmsg("the xml has multiple root nodes"))); + } +} + +/** + * convert query to xml + * @param {const XMLGenContext *} ctx - xmlgen contxt pointer + * @return {StringInfo} result + */ +static StringInfo query_to_xml_flat(XMLGenContext *ctx) +{ + StringInfo result = NULL; + int64 skip_rows = ctx->skip_rows; + errno_t et = EOK; + char *row_tag = NULL; + char *row_set_tag = NULL; + Portal portal = NULL; + + if (ctx->row_tag_name != NULL) { + row_tag = static_cast(palloc(sizeof(char) * (strlen(ctx->row_tag_name) + 1))); + et = strcpy_s(row_tag, strlen(ctx->row_tag_name) + 1, ctx->row_tag_name); + securec_check(et, "\0", "\0"); + } + + if (ctx->row_set_tag_name != NULL) { + row_set_tag = static_cast(palloc(sizeof(char) * (strlen(ctx->row_set_tag_name) + 1))); + et = strcpy_s(row_set_tag, strlen(ctx->row_set_tag_name) + 1, ctx->row_set_tag_name); + securec_check(et, "\0", "\0"); + } + + int64 null_flag = ctx->null_flag; + int64 processed_rows = 0; + int64 count_rows; + ctx->processed_rows = 0; + result = makeStringInfo(); + + if (SPI_connect() != SPI_OK_CONNECT) { + pfree_ext(row_tag); + pfree_ext(row_set_tag); + SPI_finish(); + ereport(ERROR, (errcode(ERRCODE_SPI_CONNECTION_FAILURE), errmsg("SPI_connect failed"))); + } + + if (ctx->is_cursor || ctx->skip_rows != 0 || ctx->max_rows != 0) { + if (ctx->is_cursor) { + portal = SPI_cursor_find((const char *)ctx->query_string); + } else { + SPIPlanPtr plan = NULL; + if ((plan = SPI_prepare((const char *)ctx->query_string, 0, NULL)) == NULL) { + SPI_finish(); + ereport(ERROR, (errcode(ERRCODE_SPI_PREPARE_FAILURE), errmsg("SPI_prepare failed"))); + } + + if ((portal = SPI_cursor_open(NULL, plan, NULL, NULL, false)) == NULL) { + SPI_finish(); + ereport(ERROR, (errcode(ERRCODE_SPI_CONNECTION_FAILURE), errmsg("SPI_cursor_open failed"))); + } + } + if (portal == NULL) { + pfree_ext(row_tag); + pfree_ext(row_set_tag); + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_CURSOR), errmsg("cursor \"%s\" does not exist", ctx->query_string))); + } + + if (ctx->max_rows < 0) { + SPI_cursor_fetch(portal, true, LONG_MAX); + } else { + SPI_cursor_fetch(portal, true, ctx->skip_rows + ctx->max_rows); + } + } else { + if (SPI_execute(ctx->query_string, true, 0) != SPI_OK_SELECT) { + pfree_ext(row_tag); + pfree_ext(row_set_tag); + SPI_finish(); + ereport(ERROR, (errcode(ERRCODE_SPI_CONNECTION_FAILURE), errmsg("fail to execute query"))); + } + } + + count_rows = (int64)SPI_processed; + check_xml_valid(ctx, count_rows, SPI_tuptable->tupdesc->natts); + int64 start_now = skip_rows + ctx->current_row; + if (ctx->max_rows != 0 && count_rows > start_now) { + xml_root_element_start(result, row_set_tag == NULL ? row_tag : row_set_tag, null_flag); + for (int64 i = skip_rows; i < count_rows; i++) { + SPI_sql_row_to_xml_element(i, result, null_flag, (row_set_tag == NULL || row_tag == NULL) ? NULL : row_tag, + ctx->is_convert_special_chars, ctx->item_tag_name, + (row_set_tag == NULL && row_tag == NULL) ? 0 : 1); + processed_rows++; + } + ctx->processed_rows = processed_rows; + ctx->current_row += processed_rows + skip_rows; + xml_root_element_end(result, row_set_tag == NULL ? row_tag : row_set_tag); + } + + if (!ctx->is_cursor && portal != NULL) { + SPI_cursor_close(portal); + } + SPI_finish(); + pfree_ext(row_tag); + pfree_ext(row_set_tag); + + return result; +} + +/** + * top functin to handle converting query to xml + * @param {const XMLGenContext *} ctx - xmlgen contxt pointer + * @return {StringInfo} result + */ +static StringInfo query_to_xml_internal(XMLGenContext *ctx) +{ + if (ctx->is_from_hierarchy) { + return query_to_xml_hierarchy(ctx); + } else { + return query_to_xml_flat(ctx); + } +} + +/** + * top functin to handle converting query to xml + * @param {const XMLGenContext *} ctx - xmlgen contxt pointer + * @return {StringInfo} result + */ +static void check_query_string_valid(char *query_str) +{ + if (query_str == NULL) { + ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("invalid query string"))); + } + List *queryTree = pg_parse_query(query_str); + if (queryTree == NULL || queryTree->length != 1) { + ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("can not parse sql: %s", query_str))); + } +} + +/** + * create a new XMLGenContext with specific id + * @param {int64} ctx_id + * @param {XMLGenContext *} result + */ +static XMLGenContext *create_xmlgen_context(int64 ctx_id) +{ + + if (TOP_CONTEXT == NULL) { + init_session_vars(); + } + + MemoryContext oldcontext = MemoryContextSwitchTo(TOP_CONTEXT->memctx); + XMLGenContext *ctx = static_cast(palloc0(sizeof(XMLGenContext))); + ctx->memctx = AllocSetContextCreate(TOP_CONTEXT->memctx, "XMLGENContextMemory", ALLOCSET_DEFAULT_MINSIZE, + ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE); + MemoryContextSwitchTo(oldcontext); + + oldcontext = MemoryContextSwitchTo(ctx->memctx); + + ctx->ctx_id = ctx_id; + ctx->query_string = NULL; + ctx->null_flag = 0; + ctx->row_tag_name = "ROW"; + ctx->row_set_tag_name = "ROWSET"; + ctx->is_convert_special_chars = true; + ctx->max_rows = -1; + ctx->current_row = 0; + ctx->skip_rows = 0; + ctx->processed_rows = 0; + ctx->is_from_hierarchy = false; + ctx->is_hierarchy_set_row_set_tag = false; + ctx->is_cursor = false; + ctx->is_query = false; + ctx->item_tag_name = NULL; + + MemoryContextSwitchTo(oldcontext); + return ctx; +} + +/** + * create a new XMLGenContext by sequnce, and add it to global context list + * @param {char *} query_str + * @param {bool} is_from_herarchy + * @param {bool} is_cursor + */ +static int64 new_xmlgen_context(char *query_str, bool is_from_hierarchy, bool is_cursor) +{ + MemoryContext oldcontext = NULL; + int64 new_ctx_id = ++(TOP_CONTEXT->xmlgen_context_id); + check_uint_valid(new_ctx_id); + XMLGenContext *ctx = create_xmlgen_context(new_ctx_id); + + oldcontext = MemoryContextSwitchTo(ctx->memctx); + char *qs = static_cast(palloc(sizeof(char) * strlen(query_str) + 1)); + errno_t et = strcpy_s(qs, strlen(query_str) + 1, query_str); + securec_check(et, "\0", "\0"); + ctx->query_string = qs; + MemoryContextSwitchTo(oldcontext); + ctx->is_from_hierarchy = is_from_hierarchy; + ctx->is_cursor = is_cursor; + if (TOP_CONTEXT->xmlgen_context_list != NIL && !IsA(TOP_CONTEXT->xmlgen_context_list, List)) { + TOP_CONTEXT->xmlgen_context_list = NIL; + } + + oldcontext = MemoryContextSwitchTo(TOP_CONTEXT->memctx); + TOP_CONTEXT->xmlgen_context_list = lappend(TOP_CONTEXT->xmlgen_context_list, (void *)ctx); + MemoryContextSwitchTo(oldcontext); + + return new_ctx_id; +} + +/** + * cast string to ctxhandle + * @param {string} str + * @return {ctxhandle} result + */ +Datum ctxhandle_in(PG_FUNCTION_ARGS) +{ + char *str = PG_GETARG_CSTRING(0); + int64 result; + (void)scanint8(str, false, &result); + + PG_RETURN_NUMERIC(convert_int64_to_numeric(result, 0)); +} + +/** + * cast ctxhandle to string + * @param {ctxhandle} val + * @return {string} result + */ +Datum ctxhandle_out(PG_FUNCTION_ARGS) +{ + Numeric num = PG_GETARG_NUMERIC(0); + char *str = DatumGetCString(DirectFunctionCall1(numeric_out, NumericGetDatum(num))); + PG_RETURN_CSTRING(str); +} + +/** + * close xmlgen context and release all resources, including the SQL cursor and bind and define buffers. + * @param {ctxhandle} ctx - the context handle to close. + * @return {void} + */ +Datum close_context(PG_FUNCTION_ARGS) +{ + CHECK_XML_SUPPORT(); + + if (PG_ARGISNULL(0)) { + PG_RETURN_VOID(); + } + int64 ctx_id = (int64)numeric_int16_internal(PG_GETARG_NUMERIC(0)); + check_uint_valid(ctx_id); + + XMLGenContext *ctx = get_xmlgen_context(ctx_id); + + if (ctx != NULL) { + free_xmlgen_context(ctx); + } + PG_RETURN_VOID(); +} + +/** + * converts the xml data into the escaped or unescapes XML equivalent, + * and returns XML clob data in endcoded or decoded format. + * @param {varchar2} xmlData - the xml clob data to encoded or decoded. + * @param {number} flag - the flag setting. 1 for decode, others for encode(default). + * @return {void} + */ +Datum convert_xml(PG_FUNCTION_ARGS) +{ + CHECK_XML_SUPPORT(); + + if (PG_ARGISNULL(0)) { + ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("invalid parameter"))); + } + int64 flag = 0; + if (!PG_ARGISNULL(1)) { + flag = (int64)numeric_int16_internal(PG_GETARG_NUMERIC(1)); + } + + if (flag < 0 || flag > UINT_MAX) { + PG_RETURN_NULL(); + } + + char *xmlstr = text_to_cstring(PG_GETARG_TEXT_PP(0)); + char *str = NULL; + + if (flag == 1) { + str = convert_decode((const char *)xmlstr); + } else { + str = convert_encode((const char *)xmlstr); + } + + VarChar *result = (VarChar *)cstring_to_text((const char *)str); + pfree(str); + pfree(xmlstr); + PG_RETURN_VARCHAR_P(result); +} + +/** + * converts the xml data into the escaped or unescapes XML equivalent, + * and returns XML clob data in endcoded or decoded format. + * @param {clob} xmlData - the xml clob data to encoded or decoded. + * @param {number} flag - the flag setting; 1 for decode, others for encode. + * @return {clob} result + */ +Datum convert_clob(PG_FUNCTION_ARGS) +{ + CHECK_XML_SUPPORT(); + + if (PG_ARGISNULL(0)) { + ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("invalid parameter"))); + } + int64 flag = 0; + if (!PG_ARGISNULL(1)) { + flag = (int64)numeric_int16_internal(PG_GETARG_NUMERIC(1)); + } + + char *xmlstr = text_to_cstring((const text *)PG_GETARG_BYTEA_PP(0)); + if (flag < 0 || flag > UINT_MAX) { + pfree(xmlstr); + PG_RETURN_NULL(); + } + + char *str = NULL; + + if (flag == 1) { + str = convert_decode((const char *)xmlstr); + } else { + str = convert_encode((const char *)xmlstr); + } + + xmltype *result = (xmltype *)cstring_to_text((const char *)str); + pfree(str); + pfree(xmlstr); + PG_RETURN_XML_P(result); +} + +/** + * retrieves the number of SQL rows processed when generating the xml using the getxml functions call. + * @param {ctxhandle} ctx_id + * @return {number} result + */ +Datum get_num_rows_processed(PG_FUNCTION_ARGS) +{ + CHECK_XML_SUPPORT(); + + int64 ctx_id = (int64)numeric_int16_internal(PG_GETARG_NUMERIC(0)); + check_uint_valid(ctx_id); + XMLGenContext *ctx = get_xmlgen_context(ctx_id); + if (ctx == NULL) { + PG_RETURN_NULL(); + } + PG_RETURN_NUMERIC(convert_int64_to_numeric(ctx->processed_rows, 0)); +} + +/** + * gets xml document by context id + * @param {ctxhandle} ctx_id + * @param {number} dtdOrSchema - a flag to generate a DTD or a schema, default 0 + * @return {clob} result - xml data + */ +Datum get_xml_by_ctx_id(PG_FUNCTION_ARGS) +{ + CHECK_XML_SUPPORT(); + + if (PG_ARGISNULL(0)) { + ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("invalid gms_xmlgen context id"))); + } + + int64 ctx_id = (int64)numeric_int16_internal(PG_GETARG_NUMERIC(0)); + check_uint_valid(ctx_id); + int64 dtd_or_schema = (int64)numeric_int16_internal(PG_GETARG_NUMERIC(1)); + check_uint_valid(dtd_or_schema); + XMLGenContext *ctx = get_xmlgen_context(ctx_id); + if (ctx == NULL || ctx->query_string == NULL) { + ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("invalid gms_xmlgen context found"))); + } + StringInfo si = NULL; + xmltype *res = NULL; + si = query_to_xml_internal(ctx); + res = stringinfo_to_xmltype(si); + DestroyStringInfo(si); + PG_RETURN_XML_P(res); +} + +/** + * gets xml document by query string + * @param {varchar2} query string + * @param {number} dtdOrSchema - a flag to generate a DTD or a schema, default 0 + * @return {clob} result - xml data + */ +Datum get_xml_by_query(PG_FUNCTION_ARGS) +{ + CHECK_XML_SUPPORT(); + + if (PG_ARGISNULL(0)) { + ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("invalid query string"))); + } + char *query_str = text_to_cstring(PG_GETARG_TEXT_PP(0)); + check_query_string_valid(query_str); + int64 dtd_or_schema = (int64)numeric_int16_internal(PG_GETARG_NUMERIC(1)); + check_uint_valid(dtd_or_schema); + XMLGenContext *ctx = create_xmlgen_context(0); + ctx->query_string = query_str; + StringInfo si = query_to_xml_internal(ctx); + xmltype *res = stringinfo_to_xmltype(si); + DestroyStringInfo(si); + pfree_ext(query_str); + free_xmlgen_context(ctx); + PG_RETURN_XML_P(res); +} + +/** + * generate and return a new context handle from a query string + * @param {varchar2} query string + * @return {ctxhandle} result - context id + */ +Datum new_context_by_query(PG_FUNCTION_ARGS) +{ + CHECK_XML_SUPPORT(); + + if (PG_ARGISNULL(0)) { + ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("invalid query string"))); + } + char *query_str = text_to_cstring(PG_GETARG_TEXT_PP(0)); + int64 result = new_xmlgen_context(query_str); + PG_RETURN_NUMERIC(convert_int64_to_numeric((int64)result, 0)); +} + +/** + * generate and return a new context handle from a query string in the form of a PL/SQL ref cursor + * @param {sys_refcursor} query string + * @return {ctxhandle} result - context id + */ +Datum new_context_by_cursor(PG_FUNCTION_ARGS) +{ + CHECK_XML_SUPPORT(); + + char *query_str = text_to_cstring(PG_GETARG_TEXT_PP(0)); + int64 result = new_xmlgen_context(query_str, false, true); + PG_RETURN_NUMERIC(convert_int64_to_numeric((int64)result, 0)); +} + +/** + * generate and return a new hierarchy context handle from query string + * @param {varchar2} query string + * @return {ctxhandle} result - context id + */ +Datum new_context_from_hierarchy(PG_FUNCTION_ARGS) +{ + CHECK_XML_SUPPORT(); + + if (PG_ARGISNULL(0)) { + ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("invalid query string"))); + } + char *query_str = text_to_cstring(PG_GETARG_TEXT_PP(0)); + int64 result = new_xmlgen_context(query_str, true); + PG_RETURN_NUMERIC(convert_int64_to_numeric((int64)result, 0)); +} + +/** + * restart the query and generate the XML from the first row + * used to start executing the query again, without having to create a new context + * @param {ctxhandle} ctx_id + * @return {void} + */ +Datum restart_query(PG_FUNCTION_ARGS) +{ + CHECK_XML_SUPPORT(); + + if (PG_ARGISNULL(0)) { + ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("invalid gms_xmlgen context id"))); + } + + int64 ctx_id = (int64)numeric_int16_internal(PG_GETARG_NUMERIC(0)); + check_uint_valid(ctx_id); + XMLGenContext *ctx = get_xmlgen_context(ctx_id); + if (ctx == NULL) { + PG_RETURN_NULL(); + } + + if (ctx->is_cursor) { + if (SPI_connect() != SPI_OK_CONNECT) { + SPI_finish(); + ereport(ERROR, (errcode(ERRCODE_SPI_CONNECTION_FAILURE), errmsg("SPI_connect failed"))); + } + + Portal portal = SPI_cursor_find((const char *)ctx->query_string); + if (portal == NULL) { + SPI_finish(); + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_CURSOR), errmsg("cursor \"%s\" does not exist", ctx->query_string))); + } + + SPI_cursor_move(portal, false, + ctx->current_row + (ctx->max_rows < 0 || ctx->processed_rows < ctx->max_rows ? 1 : 0)); + + SPI_finish(); + } + ctx->current_row = 0; + PG_RETURN_NULL(); +} + +/** + * set whether or not special characters in the XML data must be converted into their escaped XML equivalent + * @param {ctxhandle} ctx_id + * @param {boolean} is_convert + * @return {void} + */ +Datum set_convert_special_chars(PG_FUNCTION_ARGS) +{ + CHECK_XML_SUPPORT(); + + if (PG_ARGISNULL(0)) { + PG_RETURN_VOID(); + } + int64 ctx_id = (int64)numeric_int16_internal(PG_GETARG_NUMERIC(0)); + check_uint_valid(ctx_id); + XMLGenContext *ctx = get_xmlgen_context(ctx_id); + bool is_convert = PG_GETARG_BOOL(1); + if (ctx == NULL) { + PG_RETURN_VOID(); + } + ctx->is_convert_special_chars = is_convert; + PG_RETURN_VOID(); +} + +/** + * set the maximum number of rows to fetch from the SQL query result for every invocation of the GETXML functions call + * @param {ctxhandle} ctx_id + * @param {number} max_rows + * @return {void} + */ +Datum set_max_rows(PG_FUNCTION_ARGS) +{ + CHECK_XML_SUPPORT(); + + if (PG_ARGISNULL(0)) { + PG_RETURN_VOID(); + } + int64 ctx_id = (int64)numeric_int16_internal(PG_GETARG_NUMERIC(0)); + check_uint_valid(ctx_id); + int64 max_rows = (int64)numeric_int16_internal(PG_GETARG_NUMERIC(1)); + check_uint_valid(max_rows); + XMLGenContext *ctx = get_xmlgen_context(ctx_id); + if (ctx == NULL) { + PG_RETURN_VOID(); + } + if (ctx->is_from_hierarchy) { + ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("this operation is invalid in the hierarchy context"))); + } + + ctx->max_rows = max_rows; + PG_RETURN_VOID(); +} + +/** + * set null handling options, handled through the flag parameter setting + * @param {ctxhandle} ctx_id + * @param {number} flag - 0 for drop nulls(default); 1 for null attribute; 2 for empty tags + * @return {void} + */ +Datum set_null_handling(PG_FUNCTION_ARGS) +{ + CHECK_XML_SUPPORT(); + + int64 ctx_id = (int64)numeric_int16_internal(PG_GETARG_NUMERIC(0)); + check_uint_valid(ctx_id); + int64 flag = (int64)numeric_int16_internal(PG_GETARG_NUMERIC(1)); + check_uint_valid(flag); + XMLGenContext *ctx = get_xmlgen_context(ctx_id); + if (ctx != NULL) { + ctx->null_flag = flag; + } + PG_RETURN_VOID(); +} + +/** + * set the name of the root element of the xml + * @param {ctxhandle} ctx_id + * @param {varchar2} row_set_tag_name + * @return {void} + */ +Datum set_row_set_tag(PG_FUNCTION_ARGS) +{ + CHECK_XML_SUPPORT(); + + if (PG_ARGISNULL(0)) { + PG_RETURN_VOID(); + } + int64 ctx_id = (int64)numeric_int16_internal(PG_GETARG_NUMERIC(0)); + check_uint_valid(ctx_id); + XMLGenContext *ctx = get_xmlgen_context(ctx_id); + if (ctx == NULL) { + PG_RETURN_VOID(); + } + if (ctx->is_from_hierarchy) { + ctx->is_hierarchy_set_row_set_tag = true; + } + + if (PG_ARGISNULL(1)) { + ctx->row_set_tag_name = NULL; + PG_RETURN_VOID(); + } + + char *row_set_tag_name = text_to_cstring(PG_GETARG_TEXT_PP(1)); + MemoryContext oldcontext = MemoryContextSwitchTo(ctx->memctx); + char *row_set_tag_inner = static_cast(palloc(sizeof(char) * strlen(row_set_tag_name) + 1)); + errno_t et = strcpy_s(row_set_tag_inner, strlen(row_set_tag_name) + 1, row_set_tag_name); + securec_check(et, "\0", "\0"); + ctx->row_set_tag_name = map_sql_identifier_to_xml_name(row_set_tag_inner, false, false); + pfree_ext(row_set_tag_inner); + MemoryContextSwitchTo(oldcontext); + pfree_ext(row_set_tag_name); + PG_RETURN_VOID(); +} + +/** + * set the name of the element separating all the rows. + * @param {ctxhandle} ctx_id + * @param {varchar2} row_tag_name + * @return {void} + */ +Datum set_row_tag(PG_FUNCTION_ARGS) +{ + CHECK_XML_SUPPORT(); + + if (PG_ARGISNULL(0)) { + PG_RETURN_VOID(); + } + int64 ctx_id = (int64)numeric_int16_internal(PG_GETARG_NUMERIC(0)); + check_uint_valid(ctx_id); + XMLGenContext *ctx = get_xmlgen_context(ctx_id); + if (ctx == NULL) { + PG_RETURN_VOID(); + } + if (ctx->is_from_hierarchy) { + ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("this operation is invalid in the hierarchy context"))); + } + + if (PG_ARGISNULL(1)) { + ctx->row_tag_name = NULL; + PG_RETURN_VOID(); + } + + char *row_tag_name = text_to_cstring(PG_GETARG_TEXT_PP(1)); + MemoryContext oldcontext = MemoryContextSwitchTo(ctx->memctx); + + char *row_tag_inner = static_cast(palloc(sizeof(char) * strlen(row_tag_name) + 1)); + errno_t et = strcpy_s(row_tag_inner, strlen(row_tag_name) + 1, row_tag_name); + securec_check(et, "\0", "\0"); + ctx->row_tag_name = map_sql_identifier_to_xml_name(row_tag_inner, false, false); + pfree_ext(row_tag_inner); + MemoryContextSwitchTo(oldcontext); + pfree_ext(row_tag_name); + PG_RETURN_VOID(); +} + +/** + * skip a given number of rows before generating the XML output for every call to the getxml functions + * @param {ctxhandle} ctx_id + * @param {number} skip_rows + * @return {void} + */ +Datum set_skip_rows(PG_FUNCTION_ARGS) +{ + CHECK_XML_SUPPORT(); + + if (PG_ARGISNULL(0)) { + PG_RETURN_VOID(); + } + int64 ctx_id = (int64)numeric_int16_internal(PG_GETARG_NUMERIC(0)); + check_uint_valid(ctx_id); + int64 skip_rows = (int64)numeric_int16_internal(PG_GETARG_NUMERIC(1)); + check_uint_valid(skip_rows); + XMLGenContext *ctx = get_xmlgen_context(ctx_id); + if (ctx == NULL) { + PG_RETURN_VOID(); + } + if (ctx->is_from_hierarchy) { + ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("this operation is invalid in the hierarchy context"))); + } + + ctx->skip_rows = skip_rows; + PG_RETURN_VOID(); +} + +/** + * override the default name of the collection elements. + * @param {ctxhandle} ctx_id + * @return {void} + */ +Datum use_item_tags_for_coll(PG_FUNCTION_ARGS) +{ + CHECK_XML_SUPPORT(); + + if (PG_ARGISNULL(0)) { + PG_RETURN_VOID(); + } + int64 ctx_id = (int64)numeric_int16_internal(PG_GETARG_NUMERIC(0)); + check_uint_valid(ctx_id); + XMLGenContext *ctx = get_xmlgen_context(ctx_id); + if (ctx == NULL) { + PG_RETURN_VOID(); + } + + ctx->item_tag_name = "_ITEM"; + PG_RETURN_VOID(); +} diff --git a/contrib/gms_xmlgen/gms_xmlgen.h b/contrib/gms_xmlgen/gms_xmlgen.h new file mode 100644 index 000000000..e234cb9ef --- /dev/null +++ b/contrib/gms_xmlgen/gms_xmlgen.h @@ -0,0 +1,77 @@ +#ifndef GMS_XMLGEN_H +#define GMS_XMLGEN_H + +#ifdef USE_LIBXML +#define CHECK_XML_SUPPORT() +#else +#define CHECK_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."))) +#endif + +// non-negative number between 0 ~ 4294967295 +#define check_uint_valid(ctx_id) \ + ((ctx_id < 0 || ctx_id > UINT_MAX) \ + ? ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("value is out of range."))) \ + : (void)0) + +#define SPACE_PER_INDENTATION 2 +#define NULL_FLAG_NULL_ATTR 1 +#define NULL_FLAG_EMPTY_TAG 2 +#define MAX_DEPTH 65535 +#define XMLTYPE_STR "xmltype" +#define XML_HEADER "\n" +#define XML_XSI_ATTR "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"" + +typedef struct XMLGenContext { + MemoryContext memctx; // xmlgen memory context + int64 ctx_id; // context id for XMLGenContext + bool is_query; // is a query or not + bool is_cursor; // is a cursor or not + char *query_string; // query for xmlgen + bool is_from_hierarchy; // is in a hierarchy context + bool is_hierarchy_set_row_set_tag; // is set row_set_tag_name in a hierarchy context + bool is_convert_special_chars; // is need to encode special chars + int64 max_rows; // max row for the xml + int64 null_flag; // empty fields display, 0 for null, 1 for nil, 2 for self-close. default 0. + char *row_tag_name; // element tag name for root + char *row_set_tag_name; // element tag name for each row + int64 skip_rows; // skip the first n lines of the query result. default 0. + int64 processed_rows; // processed rows when generate xml data. + int64 current_row; // gen xml from current_row. default 0. + char *item_tag_name; // element tag name suffix for array items +} XMLGenContext; + +typedef struct XMLGenTopContext { + MemoryContext memctx; + List *xmlgen_context_list; + int64 xmlgen_context_id; +} XMLGenTopContext; + +static int64 new_xmlgen_context(char *query_str, bool is_from_hierarchy = false, bool is_cursor = false); +static char *map_sql_value_to_xml(Datum value, Oid type, bool xml_escape_strings, char *array_tag_suffix = "", + int indent_level = 0); + +extern "C" Datum ctxhandle_in(PG_FUNCTION_ARGS); +extern "C" Datum ctxhandle_out(PG_FUNCTION_ARGS); +extern "C" Datum close_context(PG_FUNCTION_ARGS); +extern "C" Datum convert_xml(PG_FUNCTION_ARGS); +extern "C" Datum convert_clob(PG_FUNCTION_ARGS); +extern "C" Datum get_num_rows_processed(PG_FUNCTION_ARGS); +extern "C" Datum get_xml_by_ctx_id(PG_FUNCTION_ARGS); +extern "C" Datum get_xml_by_query(PG_FUNCTION_ARGS); +extern "C" Datum new_context_by_query(PG_FUNCTION_ARGS); +extern "C" Datum new_context_by_cursor(PG_FUNCTION_ARGS); +extern "C" Datum new_context_from_hierarchy(PG_FUNCTION_ARGS); +extern "C" Datum restart_query(PG_FUNCTION_ARGS); +extern "C" Datum set_convert_special_chars(PG_FUNCTION_ARGS); +extern "C" Datum set_max_rows(PG_FUNCTION_ARGS); +extern "C" Datum set_null_handling(PG_FUNCTION_ARGS); +extern "C" Datum set_row_set_tag(PG_FUNCTION_ARGS); +extern "C" Datum set_row_tag(PG_FUNCTION_ARGS); +extern "C" Datum set_skip_rows(PG_FUNCTION_ARGS); +extern "C" Datum use_item_tags_for_coll(PG_FUNCTION_ARGS); +extern "C" void set_extension_index(uint32 index); +extern "C" void init_session_vars(void); + +#endif // GMS_XMLGEN_H diff --git a/contrib/gms_xmlgen/sql/gms_xmlgen.sql b/contrib/gms_xmlgen/sql/gms_xmlgen.sql new file mode 100644 index 000000000..6d2c678cb --- /dev/null +++ b/contrib/gms_xmlgen/sql/gms_xmlgen.sql @@ -0,0 +1,1182 @@ +create extension gms_xmlgen; +create extension gms_output; +select gms_output.enable(100000); +create schema gms_xmlgen_test; +set search_path = gms_xmlgen_test; +set behavior_compat_options = 'bind_procedure_searchpath'; +-- prepare data +create table t_types ( + "integer" integer, + "float" float, + "numeric" numeric(20, 6), + "boolean" boolean, + "char" char(20), + "varchar" varchar(20), + "text" text, + "blob" blob, + "raw" raw, + "date" date, + "time" time, + "timestamp" timestamp, + "json" json, + "varchar_array" varchar(20)[] +); +insert into t_types +values( + 1, + 1.23456, + 1.234567, + true, + '"''<>&char test', + 'varchar"''<>&test', + 'text test"''<>&', + 'ff', + hextoraw('ABCD'), + '2024-01-02', + '18:01:02', + '2024-02-03 19:03:04', + '{"a" : 1, "b" : 2}', + array['abc', '"''<>&', '你好'] + ), + ( + 2, + 2.23456, + 2.234567, + false, + '2"''<>&char test', + '2varchar"''<>&test', + '2text test"''<>&', + 'eeee', + hextoraw('ffff'), + '2026-03-04', + '20:12:13', + '2026-05-06 21:13:00', + '[9,8,7,6]', + array['&^%@', '"''<>&', '<&y''">'] + ), + ( + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null + ); + +-- GMS_XMLGEN.NEWCONTEXT && GMS_XMLGEN.CLOSECONTEXT +select gms_xmlgen.newcontext('select * from t_types'); +select gms_xmlgen.getxml(1); +select gms_xmlgen.closecontext(1); +-- procedure case +DECLARE +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.closecontext(xml_cxt); +END; +/ +-- newcontext by cursor +DECLARE +CURSOR xc is select * from t_types; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('xc'::refcursor); +gms_xmlgen.closecontext(xml_cxt); +END; +/ +-- newcontext by cursor expression +DECLARE +CURSOR xc is select "integer", CURSOR(select * from t_types) from t_types; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +open xc; +xml_cxt := gms_xmlgen.newcontext(xc); +gms_xmlgen.closecontext(xml_cxt); +close xc; +END; +/ +-- invalid null parameter +select gms_xmlgen.newcontext(NULL); +-- ok for invalid query sql +select gms_xmlgen.newcontext('aabbccdd'); +-- ok for closecontext NULL +select gms_xmlgen.closecontext(NULL); +-- ok for closecontext not exist id +select gms_xmlgen.closecontext(99); +-- error for closecontext invalid range +select gms_xmlgen.closecontext(-1); +select gms_xmlgen.closecontext(4294967296); + +-- GMS_XMLGEN.GETXML +-- getxml by query +DECLARE +xml_output clob; +BEGIN +xml_output := gms_xmlgen.getxml('select * from t_types'); +gms_output.put_line(xml_output); +END; +/ +-- getxml by cursor +DECLARE +CURSOR xc is select * from t_types; +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +open xc; +xml_cxt := gms_xmlgen.newcontext(xc); +xml_output := gms_xmlgen.getxml(xml_cxt); +gms_output.put_line(xml_output); +close xc; +gms_xmlgen.closecontext(xml_cxt); +END; +/ +-- getxml by cursor expression +DECLARE +CURSOR xc is select "integer", CURSOR(select * from t_types) from t_types; +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +open xc; +xml_cxt := gms_xmlgen.newcontext(xc); +xml_output := gms_xmlgen.getxml(xml_cxt); +gms_output.put_line(xml_output); +close xc; +gms_xmlgen.closecontext(xml_cxt); +END; +/ +-- getxml by context id +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +xml_output := gms_xmlgen.getxml(xml_cxt); +gms_output.put_line(xml_output); +gms_xmlgen.closecontext(xml_cxt); +END; +/ +-- getxml by context id with out parameter +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.getxml(xml_cxt, xml_output); +gms_output.put_line(xml_output); +gms_xmlgen.closecontext(xml_cxt); +END; +/ +-- no result when getxml twice without restartquery +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.getxml(xml_cxt); +xml_output := gms_xmlgen.getxml(xml_cxt); +gms_output.put_line(xml_output); +gms_xmlgen.closecontext(xml_cxt); +END; +/ +-- invalid null parameter +select gms_xmlgen.getxml(NULL); +-- invalid query sql +select gms_xmlgen.getxml('aabbccdd'); +-- invalid xmlgen context id +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.closecontext(xml_cxt); +xml_output := gms_xmlgen.getxml(xml_cxt); +END; +/ +-- invalid xmlgen context id with out parameter +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.closecontext(xml_cxt); +gms_xmlgen.getxml(xml_cxt, xml_output); +gms_output.put_line(xml_output); +END; +/ + +-- GMS_XMLGEN.GETXMLTYPE +-- getxmltype by query +DECLARE +xml_cxt gms_xmlgen.ctxhandle; +xml_type xmltype; +BEGIN +xml_type := gms_xmlgen.getxmltype('select * from t_types'); +gms_output.put_line(xml_type::text); +gms_xmlgen.closecontext(xml_cxt); +END; +/ +-- getxmltype by query with parameter 2 +DECLARE +xml_cxt gms_xmlgen.ctxhandle; +xml_type xmltype; +BEGIN +xml_type := gms_xmlgen.getxmltype('select * from t_types', 1); +gms_output.put_line(xml_type::text); +gms_xmlgen.closecontext(xml_cxt); +END; +/ +-- getxmltype by context id +DECLARE +xml_cxt gms_xmlgen.ctxhandle; +xml_type xmltype; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +xml_type := gms_xmlgen.getxmltype(xml_cxt); +gms_output.put_line(xml_type::text); +gms_xmlgen.closecontext(xml_cxt); +END; +/ +-- getxmltype by context id with parameter 2 +DECLARE +xml_cxt gms_xmlgen.ctxhandle; +xml_type xmltype; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +xml_type := gms_xmlgen.getxmltype(xml_cxt, 1); +gms_output.put_line(xml_type::text); +gms_xmlgen.closecontext(xml_cxt); +END; +/ +-- getxmltype by cursor +DECLARE +CURSOR xc is select * from t_types; +xml_cxt gms_xmlgen.ctxhandle; +xml_output xmltype; +BEGIN +open xc; +xml_cxt := gms_xmlgen.newcontext(xc); +xml_output := gms_xmlgen.getxmltype(xml_cxt); +gms_output.put_line(xml_output::text); +close xc; +gms_xmlgen.closecontext(xml_cxt); +END; +/ +-- getxmltype by cursor expression +DECLARE +CURSOR xc is select "integer", CURSOR(select * from t_types) from t_types; +xml_cxt gms_xmlgen.ctxhandle; +xml_output xmltype; +BEGIN +open xc; +xml_cxt := gms_xmlgen.newcontext(xc); +xml_output := gms_xmlgen.getxmltype(xml_cxt); +gms_output.put_line(xml_output::text); +close xc; +gms_xmlgen.closecontext(xml_cxt); +END; +/ +-- invalid null parameter +select gms_xmlgen.getxmltype(NULL); +-- invalid query sql +select gms_xmlgen.getxmltype('aabbccdd'); +-- invalid context id +DECLARE +xml_cxt gms_xmlgen.ctxhandle; +xml_type xmltype; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.closecontext(xml_cxt); +xml_type := gms_xmlgen.getxmltype(xml_cxt); +END; +/ +-- invalid parameter 2 range +select gms_xmlgen.getxmltype('select * from t_types', -1); +select gms_xmlgen.getxmltype('select * from t_types', 4294967296); + +-- GMS_XMLGEN.NEWCONTEXTFROMHIERARCHY +DECLARE +xml_output clob; +xml_cxt_from_hierarchy gms_xmlgen.ctxhandle; +BEGIN +xml_cxt_from_hierarchy := gms_xmlgen.newcontextfromhierarchy(' +SELECT "integer", xmltype(gms_xmlgen.getxml(''select * from t_types'')) +FROM t_types +START WITH "integer" = 1 OR "integer" = 2 +CONNECT BY nocycle "integer" = PRIOR "integer"'); +xml_output := gms_xmlgen.getxml(xml_cxt_from_hierarchy); +gms_output.put_line(xml_output); +gms_xmlgen.closecontext(xml_cxt_from_hierarchy); +END; +/ +-- with set row set tag +DECLARE +xml_output clob; +xml_cxt_from_hierarchy gms_xmlgen.ctxhandle; +BEGIN +xml_cxt_from_hierarchy := gms_xmlgen.newcontextfromhierarchy(' +SELECT "integer", xmltype(gms_xmlgen.getxml(''select * from t_types'')) +FROM t_types +START WITH "integer" = 1 OR "integer" = 2 +CONNECT BY nocycle "integer" = PRIOR "integer"'); +gms_xmlgen.setrowsettag(xml_cxt_from_hierarchy, 'TopTag'); +xml_output := gms_xmlgen.getxml(xml_cxt_from_hierarchy); +gms_output.put_line(xml_output); +gms_xmlgen.closecontext(xml_cxt_from_hierarchy); +END; +/ +-- error with set row tag +DECLARE +xml_output clob; +xml_cxt_from_hierarchy gms_xmlgen.ctxhandle; +BEGIN +xml_cxt_from_hierarchy := gms_xmlgen.newcontextfromhierarchy(' +SELECT "integer", xmltype(gms_xmlgen.getxml(''select * from t_types'')) +FROM t_types +START WITH "integer" = 1 OR "integer" = 2 +CONNECT BY nocycle "integer" = PRIOR "integer"'); +gms_xmlgen.setrowtag(xml_cxt_from_hierarchy, 'TopTag'); +xml_output := gms_xmlgen.getxml(xml_cxt_from_hierarchy); +gms_output.put_line(xml_output); +gms_xmlgen.closecontext(xml_cxt_from_hierarchy); +END; +/ +-- error with setmaxrows +DECLARE +xml_output clob; +xml_cxt_from_hierarchy gms_xmlgen.ctxhandle; +BEGIN +xml_cxt_from_hierarchy := gms_xmlgen.newcontextfromhierarchy(' +SELECT "integer", xmltype(gms_xmlgen.getxml(''select * from t_types'')) +FROM t_types +START WITH "integer" = 1 OR "integer" = 2 +CONNECT BY nocycle "integer" = PRIOR "integer"'); +gms_xmlgen.setmaxrows(xml_cxt_from_hierarchy, 1); +xml_output := gms_xmlgen.getxml(xml_cxt_from_hierarchy); +gms_output.put_line(xml_output); +gms_xmlgen.closecontext(xml_cxt_from_hierarchy); +END; +/ +-- error with setskiprows +DECLARE +xml_output clob; +xml_cxt_from_hierarchy gms_xmlgen.ctxhandle; +BEGIN +xml_cxt_from_hierarchy := gms_xmlgen.newcontextfromhierarchy(' +SELECT "integer", xmltype(gms_xmlgen.getxml(''select * from t_types'')) +FROM t_types +START WITH "integer" = 1 OR "integer" = 2 +CONNECT BY nocycle "integer" = PRIOR "integer"'); +gms_xmlgen.setskiprows(xml_cxt_from_hierarchy, 1); +xml_output := gms_xmlgen.getxml(xml_cxt_from_hierarchy); +gms_output.put_line(xml_output); +gms_xmlgen.closecontext(xml_cxt_from_hierarchy); +END; +/ +-- invalid null parameter +select gms_xmlgen.newcontextfromhierarchy(NULL); +-- ok for invalid query sql +select gms_xmlgen.newcontextfromhierarchy('aabbccdd'); +-- get xml error with invalid query sql +DECLARE +xml_output clob; +xml_cxt_from_hierarchy gms_xmlgen.ctxhandle; +BEGIN +xml_cxt_from_hierarchy := gms_xmlgen.newcontextfromhierarchy('aabbccdd'); +xml_output := gms_xmlgen.getxml(xml_cxt_from_hierarchy); +gms_output.put_line(xml_output); +gms_xmlgen.closecontext(xml_cxt_from_hierarchy); +END; +/ +-- get xml error with not hierarchy query sql +DECLARE +xml_output clob; +xml_cxt_from_hierarchy gms_xmlgen.ctxhandle; +BEGIN +xml_cxt_from_hierarchy := gms_xmlgen.newcontextfromhierarchy('select * from t_types'); +xml_output := gms_xmlgen.getxml(xml_cxt_from_hierarchy); +gms_output.put_line(xml_output); +gms_xmlgen.closecontext(xml_cxt_from_hierarchy); +END; +/ + +-- GMS_XMLGEN.RESTARTQUERY +-- get xml twice +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +xml_output := gms_xmlgen.getxml(xml_cxt); +gms_output.put_line(xml_output); +gms_xmlgen.restartquery(xml_cxt); +xml_output := gms_xmlgen.getxml(xml_cxt); +gms_output.put_line(xml_output); +gms_xmlgen.closecontext(xml_cxt); +END; +/ +-- ok for restartquery closed context id +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.closecontext(xml_cxt); +gms_xmlgen.restartquery(xml_cxt); +END; +/ + +-- GMS_XMLGEN.SETCONVERTSPECIALCHARS +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.setconvertspecialchars(xml_cxt, false); +xml_output := gms_xmlgen.getxml(xml_cxt); +gms_output.put_line(xml_output); +gms_xmlgen.setconvertspecialchars(xml_cxt, true); +gms_xmlgen.restartquery(xml_cxt); +xml_output := gms_xmlgen.getxml(xml_cxt); +gms_output.put_line(xml_output); +gms_xmlgen.closecontext(xml_cxt); +END; +/ +-- error for missing parameter 2 +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.setconvertspecialchars(xml_cxt); +gms_xmlgen.closecontext(xml_cxt); +END; +/ +-- ok for closed context +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.closecontext(xml_cxt); +gms_xmlgen.setconvertspecialchars(xml_cxt, true); +END; +/ + +-- GMS_XMLGEN.SETMAXROWS +-- set max rows 0 +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.setmaxrows(xml_cxt, 0); +xml_output := gms_xmlgen.getxml(xml_cxt); +gms_output.put_line(xml_output); +gms_xmlgen.closecontext(xml_cxt); +END; +/ +-- set max rows 1 +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.setmaxrows(xml_cxt, 1); +xml_output := gms_xmlgen.getxml(xml_cxt); +gms_output.put_line(xml_output); +gms_xmlgen.closecontext(xml_cxt); +END; +/ +-- parameter nums error +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.setmaxrows(xml_cxt); +gms_xmlgen.closecontext(xml_cxt); +END; +/ +-- parameter range error +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.setmaxrows(xml_cxt, -1); +gms_xmlgen.closecontext(xml_cxt); +END; +/ +-- parameter range error +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.setmaxrows(xml_cxt, 4294967296); +gms_xmlgen.closecontext(xml_cxt); +END; +/ +-- ok for closed context +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.closecontext(xml_cxt); +gms_xmlgen.setmaxrows(xml_cxt, 1); +END; +/ + +-- GMS_XMLGEN.SETNULLHANDLING +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.setnullhandling(xml_cxt, 0); +xml_output := gms_xmlgen.getxml(xml_cxt); +gms_output.put_line(xml_output); +gms_xmlgen.setnullhandling(xml_cxt, 1); +gms_xmlgen.restartquery(xml_cxt); +xml_output := gms_xmlgen.getxml(xml_cxt); +gms_output.put_line(xml_output); +gms_xmlgen.setnullhandling(xml_cxt, 2); +gms_xmlgen.restartquery(xml_cxt); +xml_output := gms_xmlgen.getxml(xml_cxt); +gms_output.put_line(xml_output); +gms_xmlgen.closecontext(xml_cxt); +END; +/ +-- other numbers > 2, the same as 0 +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.setnullhandling(xml_cxt, 3); +xml_output := gms_xmlgen.getxml(xml_cxt); +gms_output.put_line(xml_output); +gms_xmlgen.closecontext(xml_cxt); +END; +/ +-- ok for NULL +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +gms_xmlgen.setnullhandling(NULL, 1); +END; +/ +-- parameter nums error +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.setnullhandling(xml_cxt); +gms_xmlgen.closecontext(xml_cxt); +END; +/ +-- parameter range error +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.setnullhandling(xml_cxt, -1); +gms_xmlgen.closecontext(xml_cxt); +END; +/ +-- parameter range error +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.setnullhandling(xml_cxt, 4294967296); +gms_xmlgen.closecontext(xml_cxt); +END; +/ +-- ok for closed context +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.closecontext(xml_cxt); +gms_xmlgen.setnullhandling(xml_cxt, 1); +END; +/ + +-- GMS_XMLGEN.SETROWSETTAG +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.setrowsettag(xml_cxt, 'test'); +xml_output := gms_xmlgen.getxml(xml_cxt); +gms_output.put_line(xml_output); +gms_xmlgen.closecontext(xml_cxt); +END; +/ +-- error for setrowsettag NULL +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.setrowsettag(xml_cxt, NULL); +xml_output := gms_xmlgen.getxml(xml_cxt); +gms_output.put_line(xml_output); +gms_xmlgen.closecontext(xml_cxt); +END; +/ +-- ok for setrowsettag NULL with one row +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types where rownum = 1'); +gms_xmlgen.setrowsettag(xml_cxt, NULL); +xml_output := gms_xmlgen.getxml(xml_cxt); +gms_output.put_line(xml_output); +gms_xmlgen.closecontext(xml_cxt); +END; +/ +-- ok for setrowsettag context id null +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +gms_xmlgen.setrowsettag(NULL, 'test'); +END; +/ +-- parameter nums error +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.setrowsettag(xml_cxt); +gms_xmlgen.closecontext(xml_cxt); +END; +/ +-- parameter type error +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.setrowsettag(xml_cxt, true); +gms_xmlgen.closecontext(xml_cxt); +END; +/ +-- ok for closed context +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.closecontext(xml_cxt); +gms_xmlgen.setrowsettag(xml_cxt, 'test'); +END; +/ + +-- GMS_XMLGEN.SETROWTAG +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.setrowtag(xml_cxt, 'test'); +xml_output := gms_xmlgen.getxml(xml_cxt); +gms_output.put_line(xml_output); +gms_xmlgen.closecontext(xml_cxt); +END; +/ +-- ok for setrowtag NULL +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.setrowtag(xml_cxt, NULL); +xml_output := gms_xmlgen.getxml(xml_cxt); +gms_output.put_line(xml_output); +gms_xmlgen.closecontext(xml_cxt); +END; +/ +-- error for setrowsettag NULL && setrowtag NULL +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.setrowsettag(xml_cxt, NULL); +gms_xmlgen.setrowtag(xml_cxt, NULL); +xml_output := gms_xmlgen.getxml(xml_cxt); +gms_output.put_line(xml_output); +gms_xmlgen.closecontext(xml_cxt); +END; +/ +-- ok for setrowtag context id null +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +gms_xmlgen.setrowtag(NULL, 'test'); +END; +/ +-- parameter nums error +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.setrowtag(xml_cxt); +gms_xmlgen.closecontext(xml_cxt); +END; +/ +-- parameter type error +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.setrowtag(xml_cxt, true); +gms_xmlgen.closecontext(xml_cxt); +END; +/ +-- ok for closed context +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.closecontext(xml_cxt); +gms_xmlgen.setrowtag(xml_cxt, 'test'); +END; +/ + +-- GMS_XMLGEN.SETSKIPROWS +-- set skip row 0 +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.setskiprows(xml_cxt, 0); +xml_output := gms_xmlgen.getxml(xml_cxt); +gms_output.put_line(xml_output); +gms_xmlgen.closecontext(xml_cxt); +END; +/ +-- set skip row 1 +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.setskiprows(xml_cxt, 1); +xml_output := gms_xmlgen.getxml(xml_cxt); +gms_output.put_line(xml_output); +gms_xmlgen.closecontext(xml_cxt); +END; +/ +-- set skip row 2 +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.setskiprows(xml_cxt, 2); +xml_output := gms_xmlgen.getxml(xml_cxt); +gms_output.put_line(xml_output); +gms_xmlgen.closecontext(xml_cxt); +END; +/ +-- ok for setskiprows context id null +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.setskiprows(NULL, 1); +gms_xmlgen.closecontext(xml_cxt); +END; +/ +-- parameter nums error +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.setskiprows(xml_cxt); +gms_xmlgen.closecontext(xml_cxt); +END; +/ +-- parameter range error +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.setskiprows(xml_cxt, -1); +gms_xmlgen.closecontext(xml_cxt); +END; +/ +-- parameter range error +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.setskiprows(xml_cxt, 4294967296); +gms_xmlgen.closecontext(xml_cxt); +END; +/ +-- ok for closed context +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.closecontext(xml_cxt); +gms_xmlgen.setskiprows(xml_cxt, 1); +END; +/ + +-- GMS_XMLGEN.USEITEMTAGSFORCOLL +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.useitemtagsforcoll(xml_cxt); +xml_output := gms_xmlgen.getxml(xml_cxt); +gms_output.put_line(xml_output); +gms_xmlgen.closecontext(xml_cxt); +END; +/ +-- ok for useitemtagsforcoll context id NULL +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.useitemtagsforcoll(NULL); +xml_output := gms_xmlgen.getxml(xml_cxt); +gms_output.put_line(xml_output); +gms_xmlgen.closecontext(xml_cxt); +END; +/ +-- ok for closed context +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.closecontext(xml_cxt); +gms_xmlgen.useitemtagsforcoll(xml_cxt); +END; +/ + +-- GMS_XMLGEN.USENULLATTRIBUTEINDICATOR +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.usenullattributeindicator(xml_cxt); +xml_output := gms_xmlgen.getxml(xml_cxt); +gms_output.put_line(xml_output); +gms_xmlgen.closecontext(xml_cxt); +END; +/ +-- ok for parameter 2 true +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.usenullattributeindicator(xml_cxt, true); +xml_output := gms_xmlgen.getxml(xml_cxt); +gms_output.put_line(xml_output); +gms_xmlgen.closecontext(xml_cxt); +END; +/ +-- ok for parameter 2 false, the result is the same as the true's +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.usenullattributeindicator(xml_cxt, false); +xml_output := gms_xmlgen.getxml(xml_cxt); +gms_output.put_line(xml_output); +gms_xmlgen.closecontext(xml_cxt); +END; +/ +-- ok for usenullattributeindicator context id NULL +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.usenullattributeindicator(NULL); +xml_output := gms_xmlgen.getxml(xml_cxt); +gms_output.put_line(xml_output); +gms_xmlgen.closecontext(xml_cxt); +END; +/ +-- ok for closed context +DECLARE +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.closecontext(xml_cxt); +gms_xmlgen.usenullattributeindicator(xml_cxt); +END; +/ + +-- GMS_XMLGEN.GETNUMROWSPROCESSED +DECLARE +processed_row number; +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +processed_row:=gms_xmlgen.getnumrowsprocessed(xml_cxt); +gms_output.put_line(processed_row); +xml_output := gms_xmlgen.getxml(xml_cxt); +gms_output.put_line(xml_output); +processed_row:=gms_xmlgen.getnumrowsprocessed(xml_cxt); +gms_output.put_line(processed_row); +gms_xmlgen.closecontext(xml_cxt); +END; +/ +-- getnumrowsprocessed with skip rows +DECLARE +processed_row number; +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.setskiprows(xml_cxt, 1); +processed_row:=gms_xmlgen.getnumrowsprocessed(xml_cxt); +gms_output.put_line(processed_row); +xml_output := gms_xmlgen.getxml(xml_cxt); +gms_output.put_line(xml_output); +processed_row:=gms_xmlgen.getnumrowsprocessed(xml_cxt); +gms_output.put_line(processed_row); +gms_xmlgen.closecontext(xml_cxt); +END; +/ +-- getnumrowsprocessed with max rows +DECLARE +processed_row number; +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.setmaxrows(xml_cxt, 2); +processed_row:=gms_xmlgen.getnumrowsprocessed(xml_cxt); +gms_output.put_line(processed_row); +xml_output := gms_xmlgen.getxml(xml_cxt); +gms_output.put_line(xml_output); +processed_row:=gms_xmlgen.getnumrowsprocessed(xml_cxt); +gms_output.put_line(processed_row); +gms_xmlgen.closecontext(xml_cxt); +END; +/ +-- getnumrowsprocessed with skip rows && max rows +DECLARE +processed_row number; +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +gms_xmlgen.setskiprows(xml_cxt, 1); +gms_xmlgen.setmaxrows(xml_cxt, 1); +processed_row:=gms_xmlgen.getnumrowsprocessed(xml_cxt); +gms_output.put_line(processed_row); +xml_output := gms_xmlgen.getxml(xml_cxt); +gms_output.put_line(xml_output); +processed_row:=gms_xmlgen.getnumrowsprocessed(xml_cxt); +gms_output.put_line(processed_row); +gms_xmlgen.closecontext(xml_cxt); +END; +/ +-- ok for getnumrowsprocessed context id NULL +DECLARE +processed_row number; +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +xml_output := gms_xmlgen.getxml(xml_cxt); +processed_row := gms_xmlgen.getnumrowsprocessed(NULL); +gms_output.put_line(processed_row); +gms_xmlgen.closecontext(xml_cxt); +END; +/ +-- ok for closed context +DECLARE +processed_row number; +xml_output clob; +xml_cxt gms_xmlgen.ctxhandle; +BEGIN +xml_cxt := gms_xmlgen.newcontext('select * from t_types'); +xml_output := gms_xmlgen.getxml(xml_cxt); +gms_xmlgen.closecontext(xml_cxt); +processed_row := gms_xmlgen.getnumrowsprocessed(xml_cxt); +gms_output.put_line(processed_row); +END; +/ + +-- GMS_XMLGEN.CONVERT +select GMS_XMLGEN.CONVERT('"''<>&'::varchar2); +select GMS_XMLGEN.CONVERT('"''<>&'::varchar2, NULL); +select GMS_XMLGEN.CONVERT('"''<>&'::varchar2, 0); +select GMS_XMLGEN.CONVERT('"''<>&'::varchar2, 1); +select GMS_XMLGEN.CONVERT('"''<>&'::varchar2, 2); +select GMS_XMLGEN.CONVERT('"''<>&'::varchar2, -1); +select GMS_XMLGEN.CONVERT('"''<>&'::varchar2, 4294967295); +select GMS_XMLGEN.CONVERT('"''<>&'::varchar2, 4294967296); +select GMS_XMLGEN.CONVERT('"'<>&'::varchar2); +select GMS_XMLGEN.CONVERT('"'<>&'::varchar2, NULL); +select GMS_XMLGEN.CONVERT('"'<>&'::varchar2, 0); +select GMS_XMLGEN.CONVERT('"'<>&'::varchar2, 1); +select GMS_XMLGEN.CONVERT('"'<>&'::varchar2, 2); +-- would not convert +select GMS_XMLGEN.CONVERT('"&ApOS;<&gT;&Amp;'::varchar2, 1); +select pg_typeof(GMS_XMLGEN.CONVERT('"''<>&'::varchar2, 1)); +select GMS_XMLGEN.CONVERT('"''<>&'::clob); +select GMS_XMLGEN.CONVERT('"''<>&'::clob, NULL); +select GMS_XMLGEN.CONVERT('"''<>&'::clob, 0); +select GMS_XMLGEN.CONVERT('"''<>&'::clob, 1); +select GMS_XMLGEN.CONVERT('"''<>&'::clob, 2); +select GMS_XMLGEN.CONVERT('"''<>&'::clob, -1); +select GMS_XMLGEN.CONVERT('"''<>&'::clob, 4294967295); +select GMS_XMLGEN.CONVERT('"''<>&'::clob, 4294967296); +select GMS_XMLGEN.CONVERT('"'<>&'::clob); +select GMS_XMLGEN.CONVERT('"'<>&'::clob, NULL); +select GMS_XMLGEN.CONVERT('"'<>&'::clob, 0); +select GMS_XMLGEN.CONVERT('"'<>&'::clob, 1); +select GMS_XMLGEN.CONVERT('"'<>&'::clob, 2); +-- would not convert +select GMS_XMLGEN.CONVERT('"&ApOS;<&gT;&Amp;'::clob, 1); +select pg_typeof(GMS_XMLGEN.CONVERT('"''<>&'::clob, 1)); +-- error for NULL +select GMS_XMLGEN.CONVERT(NULL, 0); +select GMS_XMLGEN.CONVERT(NULL); + +-- compatibility tool usecases +DECLARE ctx GMS_xmlgen.ctxHandle; +BEGIN ctx := GMS_xmlgen.newContext('select * FROM t_types'); +GMS_xmlgen.closeContext(ctx); +GMS_output.put_line(ctx::text); +END; +/ +DECLARE res XMLType; +BEGIN res := GMS_XMLGEN.GETXMLTYPE('123'); +EXCEPTION +WHEN OTHERS THEN NULL; +END; +/ +DECLARE res GMS_XMLGEN.ctxHandle; +BEGIN res := GMS_XMLGEN.NEWCONTEXTFROMHIERARCHY('123'); +EXCEPTION +WHEN OTHERS THEN NULL; +END; +/ +DECLARE d varchar2(100); +a varchar2(100); +BEGIN d := GMS_XMLGEN.CONVERT(a); +EXCEPTION +WHEN OTHERS THEN NULL; +END; +/ +DECLARE d number; +a GMS_XMLGEN.ctxHandle; +BEGIN d := GMS_XMLGEN.GETNUMROWSPROCESSED(a); +EXCEPTION +WHEN OTHERS THEN NULL; +END; +/ +DECLARE a GMS_XMLGEN.ctxHandle; +b clob; +BEGIN b := GMS_XMLGEN.GETXML(a); +EXCEPTION +WHEN OTHERS THEN NULL; +END; +/ +DECLARE CTX GMS_XMLGEN.CTXHANDLE; +BEGIN CTX := GMS_XMLGEN.NEWCONTEXT('select * FROM t_types'); +EXCEPTION +WHEN OTHERS THEN NULL; +END; +/ +DECLARE CTX GMS_XMLGEN.CTXHANDLE; +BEGIN GMS_XMLGEN.RESTARTQUERY(CTX); +EXCEPTION +WHEN OTHERS THEN NULL; +END; +/ +DECLARE CTX GMS_XMLGEN.CTXHANDLE; +BEGIN CTX := GMS_XMLGEN.NEWCONTEXT('select * FROM t_types'); +GMS_XMLGEN.SETCONVERTSPECIALCHARS(CTX, false); +END; +/ +DECLARE CTX GMS_XMLGEN.CTXHANDLE; +BEGIN GMS_XMLGEN.SETMAXROWS(CTX, 2); +EXCEPTION +WHEN OTHERS THEN NULL; +END; +/ +DECLARE CTX GMS_XMLGEN.CTXHANDLE; +BEGIN CTX := GMS_XMLGEN.NEWCONTEXT('select * FROM t_types'); +GMS_XMLGEN.SETNULLHANDLING(CTX, 1); +END; +/ +DECLARE CTX GMS_XMLGEN.CTXHANDLE; +BEGIN CTX := GMS_XMLGEN.NEWCONTEXT('select * FROM t_types'); +GMS_XMLGEN.SETROWSETTAG(CTX, 'srst'); +END; +/ +DECLARE CTX GMS_XMLGEN.CTXHANDLE; +BEGIN CTX := GMS_XMLGEN.NEWCONTEXT('select * FROM t_types'); +GMS_XMLGEN.SETROWTAG(CTX, 'srst'); +END; +/ +DECLARE CTX GMS_XMLGEN.CTXHANDLE; +BEGIN GMS_XMLGEN.SETSKIPROWS(CTX, 5); +EXCEPTION +WHEN OTHERS THEN NULL; +END; +/ +DECLARE CTX GMS_XMLGEN.CTXHANDLE; +BEGIN GMS_XMLGEN.USEITEMTAGSFORCOLL(CTX); +EXCEPTION +WHEN OTHERS THEN NULL; +END; +/ +DECLARE CTX GMS_XMLGEN.CTXHANDLE; +BEGIN CTX := GMS_XMLGEN.NEWCONTEXT('select * FROM t_types'); +GMS_XMLGEN.USENULLATTRIBUTEINDICATOR(CTX, false); +END; +/ + +reset search_path; +drop schema gms_xmlgen_test cascade; diff --git a/src/common/backend/utils/adt/xml.cpp b/src/common/backend/utils/adt/xml.cpp index 2ffa3cc88..0f938e7f4 100644 --- a/src/common/backend/utils/adt/xml.cpp +++ b/src/common/backend/utils/adt/xml.cpp @@ -364,7 +364,7 @@ static void appendStringInfoText(StringInfo str, const text* t) } #endif -static xmltype* stringinfo_to_xmltype(StringInfo buf) +xmltype* stringinfo_to_xmltype(StringInfo buf) { return (xmltype*)cstring_to_text_with_len(buf->data, buf->len); } diff --git a/src/gausskernel/optimizer/commands/dropcmds.cpp b/src/gausskernel/optimizer/commands/dropcmds.cpp index 0703a39e6..55392914b 100644 --- a/src/gausskernel/optimizer/commands/dropcmds.cpp +++ b/src/gausskernel/optimizer/commands/dropcmds.cpp @@ -99,6 +99,7 @@ static void DropExtensionInListIsSupported(List* objname) "gms_stats", "gms_output", "gms_profiler", + "gms_xmlgen", "gms_lob", "gms_sql" #endif diff --git a/src/include/utils/xml.h b/src/include/utils/xml.h index 974efd33c..93e8e2a98 100644 --- a/src/include/utils/xml.h +++ b/src/include/utils/xml.h @@ -80,7 +80,7 @@ extern char* escape_xml(const char* str); extern char* map_sql_identifier_to_xml_name(char* ident, bool fully_escaped, bool escape_period); extern char* map_xml_name_to_sql_identifier(char* name); extern char* map_sql_value_to_xml_value(Datum value, Oid type, bool xml_escape_strings); - +extern xmltype* stringinfo_to_xmltype(StringInfo buf); /* xmltype functions */ extern Datum xmltype_extract(PG_FUNCTION_ARGS); extern Datum xmltype_extractvalue(PG_FUNCTION_ARGS);